diff options
author | Chanho Park <chanho61.park@samsung.com> | 2014-09-05 20:35:53 +0900 |
---|---|---|
committer | Chanho Park <chanho61.park@samsung.com> | 2014-09-05 20:35:53 +0900 |
commit | 16b1353a36171ae06d63fd309f4772dbfb1da113 (patch) | |
tree | cf6c297ee81aba0d9b47f23d78a889667e7bce48 /tests | |
parent | a15119db2ff5c2fdfdeb913b297bf8aa3399132e (diff) | |
download | qemu-16b1353a36171ae06d63fd309f4772dbfb1da113.tar.gz qemu-16b1353a36171ae06d63fd309f4772dbfb1da113.tar.bz2 qemu-16b1353a36171ae06d63fd309f4772dbfb1da113.zip |
Imported Upstream version 2.1.0upstream/2.1.0
Diffstat (limited to 'tests')
182 files changed, 7302 insertions, 717 deletions
diff --git a/tests/.gitignore b/tests/.gitignore index 9ba9d96b6..c71c11020 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -7,20 +7,28 @@ check-qstring check-qom-interface test-aio test-bitops -test-throttle +test-coroutine test-cutils test-hbitmap test-int128 test-iov test-mul64 +test-opts-visitor test-qapi-types.[ch] test-qapi-visit.[ch] test-qdev-global-props -test-qmp-commands.h test-qmp-commands +test-qmp-commands.h test-qmp-input-strict +test-qmp-input-visitor test-qmp-marshal.c +test-qmp-output-visitor +test-rfifolock +test-string-input-visitor +test-string-output-visitor test-thread-pool +test-throttle +test-visitor-serialization test-vmstate test-x86-cpuid test-xbzrle diff --git a/tests/Makefile b/tests/Makefile index 88f7105d0..4b2e1bbea 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -27,6 +27,8 @@ check-unit-y += tests/test-string-input-visitor$(EXESUF) gcov-files-test-string-input-visitor-y = qapi/string-input-visitor.c check-unit-y += tests/test-string-output-visitor$(EXESUF) gcov-files-test-string-output-visitor-y = qapi/string-output-visitor.c +check-unit-y += tests/test-qmp-event$(EXESUF) +gcov-files-test-qmp-event-y += qapi/qmp-event.c check-unit-y += tests/test-opts-visitor$(EXESUF) gcov-files-test-opts-visitor-y = qapi/opts-visitor.c check-unit-y += tests/test-coroutine$(EXESUF) @@ -60,6 +62,8 @@ check-unit-y += tests/test-qdev-global-props$(EXESUF) check-unit-y += tests/check-qom-interface$(EXESUF) gcov-files-check-qom-interface-y = qom/object.c check-unit-$(CONFIG_POSIX) += tests/test-vmstate$(EXESUF) +check-unit-y += tests/test-qemu-opts$(EXESUF) +gcov-files-test-qemu-opts-y = qom/test-qemu-opts.c check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh @@ -107,12 +111,22 @@ check-qtest-pci-y += tests/ne2000-test$(EXESUF) gcov-files-pci-y += hw/net/ne2000.c check-qtest-pci-y += tests/nvme-test$(EXESUF) gcov-files-pci-y += hw/block/nvme.c +check-qtest-pci-y += tests/ac97-test$(EXESUF) +gcov-files-pci-y += hw/audio/ac97.c +check-qtest-pci-y += tests/es1370-test$(EXESUF) +gcov-files-pci-y += hw/audio/es1370.c check-qtest-pci-y += $(check-qtest-virtio-y) gcov-files-pci-y += $(gcov-files-virtio-y) hw/virtio/virtio-pci.c check-qtest-pci-y += tests/tpci200-test$(EXESUF) gcov-files-pci-y += hw/ipack/tpci200.c check-qtest-pci-y += $(check-qtest-ipack-y) gcov-files-pci-y += $(gcov-files-ipack-y) +check-qtest-pci-y += tests/display-vga-test$(EXESUF) +gcov-files-pci-y += hw/display/vga.c +gcov-files-pci-y += hw/display/cirrus_vga.c +gcov-files-pci-y += hw/display/vga-pci.c +check-qtest-pci-y += tests/intel-hda-test$(EXESUF) +gcov-files-pci-y += hw/audio/intel-hda.c hw/audio/hda-codec.c check-qtest-i386-y = tests/endianness-test$(EXESUF) check-qtest-i386-y += tests/fdc-test$(EXESUF) @@ -121,12 +135,14 @@ check-qtest-i386-y += tests/ide-test$(EXESUF) check-qtest-i386-y += tests/hd-geo-test$(EXESUF) gcov-files-i386-y += hw/block/hd-geometry.c check-qtest-i386-y += tests/boot-order-test$(EXESUF) -check-qtest-i386-y += tests/acpi-test$(EXESUF) +check-qtest-i386-y += tests/bios-tables-test$(EXESUF) check-qtest-i386-y += tests/rtc-test$(EXESUF) check-qtest-i386-y += tests/i440fx-test$(EXESUF) check-qtest-i386-y += tests/fw_cfg-test$(EXESUF) check-qtest-i386-y += tests/blockdev-test$(EXESUF) check-qtest-i386-y += tests/qdev-monitor-test$(EXESUF) +check-qtest-i386-y += tests/wdt_ib700-test$(EXESUF) +gcov-files-i386-y += hw/watchdog/watchdog.c hw/watchdog/wdt_ib700.c check-qtest-i386-y += $(check-qtest-pci-y) gcov-files-i386-y += $(gcov-files-pci-y) check-qtest-i386-y += tests/vmxnet3-test$(EXESUF) @@ -137,6 +153,14 @@ check-qtest-i386-y += tests/pvpanic-test$(EXESUF) gcov-files-i386-y += i386-softmmu/hw/misc/pvpanic.c check-qtest-i386-y += tests/i82801b11-test$(EXESUF) gcov-files-i386-y += hw/pci-bridge/i82801b11.c +check-qtest-i386-y += tests/ioh3420-test$(EXESUF) +gcov-files-i386-y += hw/pci-bridge/ioh3420.c +check-qtest-i386-y += tests/usb-hcd-ehci-test$(EXESUF) +gcov-files-i386-y += hw/usb/hcd-ehci.c +gcov-files-i386-y += hw/usb/hcd-uhci.c +gcov-files-i386-y += hw/usb/dev-hid.c +gcov-files-i386-y += hw/usb/dev-storage.c +check-qtest-i386-$(CONFIG_LINUX) += tests/vhost-user-test$(EXESUF) check-qtest-x86_64-y = $(check-qtest-i386-y) gcov-files-i386-y += i386-softmmu/hw/timer/mc146818rtc.c gcov-files-x86_64-y = $(subst i386-softmmu/,x86_64-softmmu/,$(gcov-files-i386-y)) @@ -175,9 +199,14 @@ check-qapi-schema-y := $(addprefix tests/qapi-schema/, \ duplicate-key.json union-invalid-base.json flat-union-no-base.json \ flat-union-invalid-discriminator.json \ flat-union-invalid-branch-key.json flat-union-reverse-define.json \ - flat-union-string-discriminator.json) + flat-union-string-discriminator.json \ + include-simple.json include-relpath.json include-format-err.json \ + include-non-file.json include-no-file.json include-before-err.json \ + include-nested-err.json include-self-cycle.json include-cycle.json \ + include-repetition.json event-nest-struct.json) -GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h +GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h \ + tests/test-qmp-commands.h tests/test-qapi-event.h test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \ tests/check-qlist.o tests/check-qfloat.o tests/check-qjson.o \ @@ -186,9 +215,10 @@ test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \ tests/test-qmp-input-visitor.o tests/test-qmp-input-strict.o \ tests/test-qmp-commands.o tests/test-visitor-serialization.o \ tests/test-x86-cpuid.o tests/test-mul64.o tests/test-int128.o \ - tests/test-opts-visitor.o + tests/test-opts-visitor.o tests/test-qmp-event.o -test-qapi-obj-y = tests/test-qapi-visit.o tests/test-qapi-types.o +test-qapi-obj-y = tests/test-qapi-visit.o tests/test-qapi-types.o \ + tests/test-qapi-event.o $(test-obj-y): QEMU_INCLUDES += -Itests QEMU_CFLAGS += -I$(SRC_PATH)/tests @@ -227,16 +257,28 @@ tests/test-vmstate$(EXESUF): tests/test-vmstate.o \ tests/test-qapi-types.c tests/test-qapi-types.h :\ $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py - $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o tests -p "test-" < $<, " GEN $@") + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \ + $(gen-out-type) -o tests -p "test-" -i $<, \ + " GEN $@") tests/test-qapi-visit.c tests/test-qapi-visit.h :\ $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-visit.py - $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o tests -p "test-" < $<, " GEN $@") + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py \ + $(gen-out-type) -o tests -p "test-" -i $<, \ + " GEN $@") tests/test-qmp-commands.h tests/test-qmp-marshal.c :\ $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py - $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o tests -p "test-" < $<, " GEN $@") + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \ + $(gen-out-type) -o tests -p "test-" -i $<, \ + " GEN $@") +tests/test-qapi-event.c tests/test-qapi-event.h :\ +$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-event.py + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-event.py \ + $(gen-out-type) -o tests -p "test-" -i $<, \ + " GEN $@") tests/test-string-output-visitor$(EXESUF): tests/test-string-output-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a tests/test-string-input-visitor$(EXESUF): tests/test-string-input-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a +tests/test-qmp-event$(EXESUF): tests/test-qmp-event.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a tests/test-qmp-output-visitor$(EXESUF): tests/test-qmp-output-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a tests/test-qmp-input-visitor$(EXESUF): tests/test-qmp-input-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a tests/test-qmp-input-strict$(EXESUF): tests/test-qmp-input-strict.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a @@ -261,7 +303,7 @@ tests/fdc-test$(EXESUF): tests/fdc-test.o tests/ide-test$(EXESUF): tests/ide-test.o $(libqos-pc-obj-y) tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o tests/boot-order-test$(EXESUF): tests/boot-order-test.o $(libqos-obj-y) -tests/acpi-test$(EXESUF): tests/acpi-test.o $(libqos-obj-y) +tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o $(libqos-obj-y) tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y) tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y) tests/fw_cfg-test$(EXESUF): tests/fw_cfg-test.o $(libqos-pc-obj-y) @@ -271,6 +313,7 @@ tests/pcnet-test$(EXESUF): tests/pcnet-test.o tests/eepro100-test$(EXESUF): tests/eepro100-test.o tests/vmxnet3-test$(EXESUF): tests/vmxnet3-test.o tests/ne2000-test$(EXESUF): tests/ne2000-test.o +tests/wdt_ib700-test$(EXESUF): tests/wdt_ib700-test.o tests/virtio-balloon-test$(EXESUF): tests/virtio-balloon-test.o tests/virtio-blk-test$(EXESUF): tests/virtio-blk-test.o tests/virtio-net-test$(EXESUF): tests/virtio-net-test.o @@ -280,6 +323,7 @@ tests/virtio-9p-test$(EXESUF): tests/virtio-9p-test.o tests/virtio-serial-test$(EXESUF): tests/virtio-serial-test.o tests/virtio-console-test$(EXESUF): tests/virtio-console-test.o tests/tpci200-test$(EXESUF): tests/tpci200-test.o +tests/display-vga-test$(EXESUF): tests/display-vga-test.o tests/ipoctal232-test$(EXESUF): tests/ipoctal232-test.o tests/qom-test$(EXESUF): tests/qom-test.o tests/blockdev-test$(EXESUF): tests/blockdev-test.o $(libqos-pc-obj-y) @@ -287,7 +331,18 @@ tests/qdev-monitor-test$(EXESUF): tests/qdev-monitor-test.o $(libqos-pc-obj-y) tests/nvme-test$(EXESUF): tests/nvme-test.o tests/pvpanic-test$(EXESUF): tests/pvpanic-test.o tests/i82801b11-test$(EXESUF): tests/i82801b11-test.o +tests/ac97-test$(EXESUF): tests/ac97-test.o +tests/es1370-test$(EXESUF): tests/es1370-test.o +tests/intel-hda-test$(EXESUF): tests/intel-hda-test.o +tests/ioh3420-test$(EXESUF): tests/ioh3420-test.o +tests/usb-hcd-ehci-test$(EXESUF): tests/usb-hcd-ehci-test.o $(libqos-pc-obj-y) +tests/vhost-user-test$(EXESUF): tests/vhost-user-test.o qemu-char.o qemu-timer.o $(qtest-obj-y) tests/qemu-iotests/socket_scm_helper$(EXESUF): tests/qemu-iotests/socket_scm_helper.o +tests/test-qemu-opts$(EXESUF): tests/test-qemu-opts.o libqemuutil.a libqemustub.a + +ifeq ($(CONFIG_POSIX),y) +LIBS += -lutil +endif # QTest rules @@ -379,9 +434,14 @@ check-tests/test-qapi.py: tests/test-qapi.py .PHONY: $(patsubst %, check-%, $(check-qapi-schema-y)) $(patsubst %, check-%, $(check-qapi-schema-y)): check-%.json: $(SRC_PATH)/%.json - $(call quiet-command, PYTHONPATH=$(SRC_PATH)/scripts $(PYTHON) $(SRC_PATH)/tests/qapi-schema/test-qapi.py <$^ >$*.test.out 2>$*.test.err; echo $$? >$*.test.exit, " TEST $*.out") + $(call quiet-command, PYTHONPATH=$(SRC_PATH)/scripts \ + $(PYTHON) $(SRC_PATH)/tests/qapi-schema/test-qapi.py \ + $^ >$*.test.out 2>$*.test.err; \ + echo $$? >$*.test.exit, \ + " TEST $*.out") @diff -q $(SRC_PATH)/$*.out $*.test.out - @diff -q $(SRC_PATH)/$*.err $*.test.err + @# Sanitize error messages (make them independent of build directory) + @perl -p -e 's|\Q$(SRC_PATH)\E/||g' $*.test.err | diff -q $(SRC_PATH)/$*.err - @diff -q $(SRC_PATH)/$*.exit $*.test.exit # Consolidated targets diff --git a/tests/ac97-test.c b/tests/ac97-test.c new file mode 100644 index 000000000..af30ea1dd --- /dev/null +++ b/tests/ac97-test.c @@ -0,0 +1,33 @@ +/* + * QTest testcase for AC97 + * + * Copyright (c) 2014 SUSE LINUX Products GmbH + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include <glib.h> +#include <string.h> +#include "libqtest.h" +#include "qemu/osdep.h" + +/* Tests only initialization so far. TODO: Replace with functional tests */ +static void nop(void) +{ +} + +int main(int argc, char **argv) +{ + int ret; + + g_test_init(&argc, &argv, NULL); + qtest_add_func("/ac97/nop", nop); + + qtest_start("-device AC97"); + ret = g_test_run(); + + qtest_end(); + + return ret; +} diff --git a/tests/acpi-test-data/pc/DSDT b/tests/acpi-test-data/pc/DSDT Binary files differindex d0bb3de79..d37ec3445 100644 --- a/tests/acpi-test-data/pc/DSDT +++ b/tests/acpi-test-data/pc/DSDT diff --git a/tests/acpi-test-data/pc/SSDT b/tests/acpi-test-data/pc/SSDT Binary files differindex c987fb237..eb2d8b698 100644 --- a/tests/acpi-test-data/pc/SSDT +++ b/tests/acpi-test-data/pc/SSDT diff --git a/tests/acpi-test-data/q35/DSDT b/tests/acpi-test-data/q35/DSDT Binary files differindex fc5b97000..2d2bc4ada 100644 --- a/tests/acpi-test-data/q35/DSDT +++ b/tests/acpi-test-data/q35/DSDT diff --git a/tests/acpi-test-data/q35/SSDT b/tests/acpi-test-data/q35/SSDT Binary files differindex 919963875..778b79bf4 100644 --- a/tests/acpi-test-data/q35/SSDT +++ b/tests/acpi-test-data/q35/SSDT diff --git a/tests/acpi-test.c b/tests/bios-tables-test.c index 76fbccfa4..045eb2757 100644 --- a/tests/acpi-test.c +++ b/tests/bios-tables-test.c @@ -18,6 +18,8 @@ #include "libqtest.h" #include "qemu/compiler.h" #include "hw/i386/acpi-defs.h" +#include "hw/i386/smbios.h" +#include "qemu/bitmap.h" #define MACHINE_PC "pc" #define MACHINE_Q35 "q35" @@ -46,6 +48,8 @@ typedef struct { uint32_t *rsdt_tables_addr; int rsdt_tables_nr; GArray *tables; + uint32_t smbios_ep_addr; + struct smbios_entry_point smbios_ep_table; } test_data; #define LOW(x) ((x) & 0xff) @@ -483,7 +487,11 @@ static GString *normalize_asl(gchar *asl_code) /* strip comments (different generation days) */ comment = g_strstr_len(asl->str, asl->len, COMMENT_END); if (comment) { - asl = g_string_erase(asl, 0, comment + sizeof(COMMENT_END) - asl->str); + comment += strlen(COMMENT_END); + while (*comment == '\n') { + comment++; + } + asl = g_string_erase(asl, 0, comment - asl->str); } /* strip def block name (it has file path in it) */ @@ -581,6 +589,124 @@ static void test_acpi_asl(test_data *data) free_test_data(&exp_data); } +static void test_smbios_ep_address(test_data *data) +{ + uint32_t off; + + /* find smbios entry point structure */ + for (off = 0xf0000; off < 0x100000; off += 0x10) { + uint8_t sig[] = "_SM_"; + int i; + + for (i = 0; i < sizeof sig - 1; ++i) { + sig[i] = readb(off + i); + } + + if (!memcmp(sig, "_SM_", sizeof sig)) { + break; + } + } + + g_assert_cmphex(off, <, 0x100000); + data->smbios_ep_addr = off; +} + +static void test_smbios_ep_table(test_data *data) +{ + struct smbios_entry_point *ep_table = &data->smbios_ep_table; + uint32_t addr = data->smbios_ep_addr; + + ACPI_READ_ARRAY(ep_table->anchor_string, addr); + g_assert(!memcmp(ep_table->anchor_string, "_SM_", 4)); + ACPI_READ_FIELD(ep_table->checksum, addr); + ACPI_READ_FIELD(ep_table->length, addr); + ACPI_READ_FIELD(ep_table->smbios_major_version, addr); + ACPI_READ_FIELD(ep_table->smbios_minor_version, addr); + ACPI_READ_FIELD(ep_table->max_structure_size, addr); + ACPI_READ_FIELD(ep_table->entry_point_revision, addr); + ACPI_READ_ARRAY(ep_table->formatted_area, addr); + ACPI_READ_ARRAY(ep_table->intermediate_anchor_string, addr); + g_assert(!memcmp(ep_table->intermediate_anchor_string, "_DMI_", 5)); + ACPI_READ_FIELD(ep_table->intermediate_checksum, addr); + ACPI_READ_FIELD(ep_table->structure_table_length, addr); + g_assert_cmpuint(ep_table->structure_table_length, >, 0); + ACPI_READ_FIELD(ep_table->structure_table_address, addr); + ACPI_READ_FIELD(ep_table->number_of_structures, addr); + g_assert_cmpuint(ep_table->number_of_structures, >, 0); + ACPI_READ_FIELD(ep_table->smbios_bcd_revision, addr); + g_assert(!acpi_checksum((uint8_t *)ep_table, sizeof *ep_table)); + g_assert(!acpi_checksum((uint8_t *)ep_table + 0x10, + sizeof *ep_table - 0x10)); +} + +static inline bool smbios_single_instance(uint8_t type) +{ + switch (type) { + case 0: + case 1: + case 2: + case 3: + case 16: + case 32: + case 127: + return true; + default: + return false; + } +} + +static void test_smbios_structs(test_data *data) +{ + DECLARE_BITMAP(struct_bitmap, SMBIOS_MAX_TYPE+1) = { 0 }; + struct smbios_entry_point *ep_table = &data->smbios_ep_table; + uint32_t addr = ep_table->structure_table_address; + int i, len, max_len = 0; + uint8_t type, prv, crt; + uint8_t required_struct_types[] = {0, 1, 3, 4, 16, 17, 19, 32, 127}; + + /* walk the smbios tables */ + for (i = 0; i < ep_table->number_of_structures; i++) { + + /* grab type and formatted area length from struct header */ + type = readb(addr); + g_assert_cmpuint(type, <=, SMBIOS_MAX_TYPE); + len = readb(addr + 1); + + /* single-instance structs must not have been encountered before */ + if (smbios_single_instance(type)) { + g_assert(!test_bit(type, struct_bitmap)); + } + set_bit(type, struct_bitmap); + + /* seek to end of unformatted string area of this struct ("\0\0") */ + prv = crt = 1; + while (prv || crt) { + prv = crt; + crt = readb(addr + len); + len++; + } + + /* keep track of max. struct size */ + if (max_len < len) { + max_len = len; + g_assert_cmpuint(max_len, <=, ep_table->max_structure_size); + } + + /* start of next structure */ + addr += len; + } + + /* total table length and max struct size must match entry point values */ + g_assert_cmpuint(ep_table->structure_table_length, ==, + addr - ep_table->structure_table_address); + g_assert_cmpuint(ep_table->max_structure_size, ==, max_len); + + /* required struct types must all be present */ + for (i = 0; i < ARRAY_SIZE(required_struct_types); i++) { + g_assert(test_bit(required_struct_types[i], struct_bitmap)); + } +} + static void test_acpi_one(const char *params, test_data *data) { char *args; @@ -633,6 +759,10 @@ static void test_acpi_one(const char *params, test_data *data) } } + test_smbios_ep_address(data); + test_smbios_ep_table(data); + test_smbios_structs(data); + qtest_quit(global_qtest); g_free(args); } diff --git a/tests/check-qdict.c b/tests/check-qdict.c index 2ad0f7827..a9296f083 100644 --- a/tests/check-qdict.c +++ b/tests/check-qdict.c @@ -444,6 +444,92 @@ static void qdict_array_split_test(void) QDECREF(test_dict); } +static void qdict_join_test(void) +{ + QDict *dict1, *dict2; + bool overwrite = false; + int i; + + dict1 = qdict_new(); + dict2 = qdict_new(); + + + /* Test everything once without overwrite and once with */ + do + { + /* Test empty dicts */ + qdict_join(dict1, dict2, overwrite); + + g_assert(qdict_size(dict1) == 0); + g_assert(qdict_size(dict2) == 0); + + + /* First iteration: Test movement */ + /* Second iteration: Test empty source and non-empty destination */ + qdict_put(dict2, "foo", qint_from_int(42)); + + for (i = 0; i < 2; i++) { + qdict_join(dict1, dict2, overwrite); + + g_assert(qdict_size(dict1) == 1); + g_assert(qdict_size(dict2) == 0); + + g_assert(qdict_get_int(dict1, "foo") == 42); + } + + + /* Test non-empty source and destination without conflict */ + qdict_put(dict2, "bar", qint_from_int(23)); + + qdict_join(dict1, dict2, overwrite); + + g_assert(qdict_size(dict1) == 2); + g_assert(qdict_size(dict2) == 0); + + g_assert(qdict_get_int(dict1, "foo") == 42); + g_assert(qdict_get_int(dict1, "bar") == 23); + + + /* Test conflict */ + qdict_put(dict2, "foo", qint_from_int(84)); + + qdict_join(dict1, dict2, overwrite); + + g_assert(qdict_size(dict1) == 2); + g_assert(qdict_size(dict2) == !overwrite); + + g_assert(qdict_get_int(dict1, "foo") == overwrite ? 84 : 42); + g_assert(qdict_get_int(dict1, "bar") == 23); + + if (!overwrite) { + g_assert(qdict_get_int(dict2, "foo") == 84); + } + + + /* Check the references */ + g_assert(qdict_get(dict1, "foo")->refcnt == 1); + g_assert(qdict_get(dict1, "bar")->refcnt == 1); + + if (!overwrite) { + g_assert(qdict_get(dict2, "foo")->refcnt == 1); + } + + + /* Clean up */ + qdict_del(dict1, "foo"); + qdict_del(dict1, "bar"); + + if (!overwrite) { + qdict_del(dict2, "foo"); + } + } + while (overwrite ^= true); + + + QDECREF(dict1); + QDECREF(dict2); +} + /* * Errors test-cases */ @@ -584,6 +670,7 @@ int main(int argc, char **argv) g_test_add_func("/public/iterapi", qdict_iterapi_test); g_test_add_func("/public/flatten", qdict_flatten_test); g_test_add_func("/public/array_split", qdict_array_split_test); + g_test_add_func("/public/join", qdict_join_test); g_test_add_func("/errors/put_exists", qdict_put_exists_test); g_test_add_func("/errors/get_not_exists", qdict_get_not_exists_test); diff --git a/tests/check-qjson.c b/tests/check-qjson.c index 4e7454810..95497a037 100644 --- a/tests/check-qjson.c +++ b/tests/check-qjson.c @@ -45,6 +45,13 @@ static void escaped_string(void) { "\"single byte utf-8 \\u0020\"", "single byte utf-8 ", .skip = 1 }, { "\"double byte utf-8 \\u00A2\"", "double byte utf-8 \xc2\xa2" }, { "\"triple byte utf-8 \\u20AC\"", "triple byte utf-8 \xe2\x82\xac" }, + { "'\\b'", "\b", .skip = 1 }, + { "'\\f'", "\f", .skip = 1 }, + { "'\\n'", "\n", .skip = 1 }, + { "'\\r'", "\r", .skip = 1 }, + { "'\\t'", "\t", .skip = 1 }, + { "'\\/'", "/", .skip = 1 }, + { "'\\\\'", "\\", .skip = 1 }, {} }; diff --git a/tests/display-vga-test.c b/tests/display-vga-test.c new file mode 100644 index 000000000..17f59101e --- /dev/null +++ b/tests/display-vga-test.c @@ -0,0 +1,52 @@ +/* + * QTest testcase for vga cards + * + * Copyright (c) 2014 Red Hat, Inc + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include <glib.h> +#include <string.h> +#include "libqtest.h" +#include "qemu/osdep.h" + +static void pci_cirrus(void) +{ + qtest_start("-vga none -device cirrus-vga"); + qtest_end(); +} + +static void pci_stdvga(void) +{ + qtest_start("-vga none -device VGA"); + qtest_end(); +} + +static void pci_secondary(void) +{ + qtest_start("-vga none -device secondary-vga"); + qtest_end(); +} + +static void pci_multihead(void) +{ + qtest_start("-vga none -device VGA -device secondary-vga"); + qtest_end(); +} + +int main(int argc, char **argv) +{ + int ret; + + g_test_init(&argc, &argv, NULL); + + qtest_add_func("/display/pci/cirrus", pci_cirrus); + qtest_add_func("/display/pci/stdvga", pci_stdvga); + qtest_add_func("/display/pci/secondary", pci_secondary); + qtest_add_func("/display/pci/multihead", pci_multihead); + ret = g_test_run(); + + return ret; +} diff --git a/tests/e1000-test.c b/tests/e1000-test.c index a8ba2fc0a..81f164d9e 100644 --- a/tests/e1000-test.c +++ b/tests/e1000-test.c @@ -13,21 +13,40 @@ #include "qemu/osdep.h" /* Tests only initialization so far. TODO: Replace with functional tests */ -static void nop(void) +static void test_device(gconstpointer data) { + const char *model = data; + QTestState *s; + char *args; + + args = g_strdup_printf("-device %s", model); + s = qtest_start(args); + + if (s) { + qtest_quit(s); + } + g_free(args); } +static const char *models[] = { + "e1000", + "e1000-82540em", + "e1000-82544gc", + "e1000-82545em", +}; + int main(int argc, char **argv) { - int ret; + int i; g_test_init(&argc, &argv, NULL); - qtest_add_func("/e1000/nop", nop); - qtest_start("-device e1000"); - ret = g_test_run(); + for (i = 0; i < ARRAY_SIZE(models); i++) { + char *path; - qtest_end(); + path = g_strdup_printf("/%s/e1000/%s", qtest_get_arch(), models[i]); + g_test_add_data_func(path, models[i], test_device); + } - return ret; + return g_test_run(); } diff --git a/tests/es1370-test.c b/tests/es1370-test.c new file mode 100644 index 000000000..cc23fb5c6 --- /dev/null +++ b/tests/es1370-test.c @@ -0,0 +1,33 @@ +/* + * QTest testcase for ES1370 + * + * Copyright (c) 2014 SUSE LINUX Products GmbH + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include <glib.h> +#include <string.h> +#include "libqtest.h" +#include "qemu/osdep.h" + +/* Tests only initialization so far. TODO: Replace with functional tests */ +static void nop(void) +{ +} + +int main(int argc, char **argv) +{ + int ret; + + g_test_init(&argc, &argv, NULL); + qtest_add_func("/es1370/nop", nop); + + qtest_start("-device ES1370"); + ret = g_test_run(); + + qtest_end(); + + return ret; +} diff --git a/tests/fdc-test.c b/tests/fdc-test.c index 37096dcc1..203074cda 100644 --- a/tests/fdc-test.c +++ b/tests/fdc-test.c @@ -65,7 +65,7 @@ enum { DSKCHG = 0x80, }; -char test_image[] = "/tmp/qtest.XXXXXX"; +static char test_image[] = "/tmp/qtest.XXXXXX"; #define assert_bit_set(data, mask) g_assert_cmphex((data) & (mask), ==, (mask)) #define assert_bit_clear(data, mask) g_assert_cmphex((data) & (mask), ==, 0) @@ -291,7 +291,7 @@ static void test_media_insert(void) /* Insert media in drive. DSKCHK should not be reset until a step pulse * is sent. */ qmp_discard_response("{'execute':'change', 'arguments':{" - " 'device':'floppy0', 'target': '%s' }}", + " 'device':'floppy0', 'target': %s }}", test_image); qmp_discard_response(""); /* ignore event (FIXME open -> open transition?!) */ diff --git a/tests/intel-hda-test.c b/tests/intel-hda-test.c new file mode 100644 index 000000000..d89b407dc --- /dev/null +++ b/tests/intel-hda-test.c @@ -0,0 +1,45 @@ +/* + * QTest testcase for Intel HDA + * + * Copyright (c) 2014 SUSE LINUX Products GmbH + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include <glib.h> +#include <string.h> +#include "libqtest.h" +#include "qemu/osdep.h" + +#define HDA_ID "hda0" +#define CODEC_DEVICES " -device hda-output,bus=" HDA_ID ".0" \ + " -device hda-micro,bus=" HDA_ID ".0" \ + " -device hda-duplex,bus=" HDA_ID ".0" + +/* Tests only initialization so far. TODO: Replace with functional tests */ +static void ich6_test(void) +{ + qtest_start("-device intel-hda,id=" HDA_ID CODEC_DEVICES); + qtest_end(); +} + +static void ich9_test(void) +{ + qtest_start("-machine q35 -device ich9-intel-hda,bus=pcie.0,addr=1b.0,id=" + HDA_ID CODEC_DEVICES); + qtest_end(); +} + +int main(int argc, char **argv) +{ + int ret; + + g_test_init(&argc, &argv, NULL); + qtest_add_func("/intel-hda/ich6", ich6_test); + qtest_add_func("/intel-hda/ich9", ich9_test); + + ret = g_test_run(); + + return ret; +} diff --git a/tests/ioh3420-test.c b/tests/ioh3420-test.c new file mode 100644 index 000000000..c991a5f87 --- /dev/null +++ b/tests/ioh3420-test.c @@ -0,0 +1,34 @@ +/* + * QTest testcase for Intel X58 north bridge IOH + * + * Copyright (c) 2014 SUSE LINUX Products GmbH + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include <glib.h> +#include <string.h> +#include "libqtest.h" +#include "qemu/osdep.h" + +/* Tests only initialization so far. TODO: Replace with functional tests */ +static void nop(void) +{ +} + +int main(int argc, char **argv) +{ + int ret; + + g_test_init(&argc, &argv, NULL); + qtest_add_func("/ioh3420/nop", nop); + + qtest_start("-machine q35 -device ioh3420,bus=pcie.0,addr=1c.0,port=1," + "chassis=1,multifunction=on"); + ret = g_test_run(); + + qtest_end(); + + return ret; +} diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c index bf741a43a..4adf4006a 100644 --- a/tests/libqos/pci-pc.c +++ b/tests/libqos/pci-pc.c @@ -41,7 +41,7 @@ static uint8_t qpci_pc_io_readb(QPCIBus *bus, void *addr) if (port < 0x10000) { value = inb(port); } else { - memread(port, &value, sizeof(value)); + value = readb(port); } return value; @@ -55,7 +55,7 @@ static uint16_t qpci_pc_io_readw(QPCIBus *bus, void *addr) if (port < 0x10000) { value = inw(port); } else { - memread(port, &value, sizeof(value)); + value = readw(port); } return value; @@ -69,7 +69,7 @@ static uint32_t qpci_pc_io_readl(QPCIBus *bus, void *addr) if (port < 0x10000) { value = inl(port); } else { - memread(port, &value, sizeof(value)); + value = readl(port); } return value; @@ -82,7 +82,7 @@ static void qpci_pc_io_writeb(QPCIBus *bus, void *addr, uint8_t value) if (port < 0x10000) { outb(port, value); } else { - memwrite(port, &value, sizeof(value)); + writeb(port, value); } } @@ -93,7 +93,7 @@ static void qpci_pc_io_writew(QPCIBus *bus, void *addr, uint16_t value) if (port < 0x10000) { outw(port, value); } else { - memwrite(port, &value, sizeof(value)); + writew(port, value); } } @@ -104,7 +104,7 @@ static void qpci_pc_io_writel(QPCIBus *bus, void *addr, uint32_t value) if (port < 0x10000) { outl(port, value); } else { - memwrite(port, &value, sizeof(value)); + writel(port, value); } } diff --git a/tests/libqos/pci.c b/tests/libqos/pci.c index 7e0907b51..c9a0b9134 100644 --- a/tests/libqos/pci.c +++ b/tests/libqos/pci.c @@ -103,7 +103,7 @@ void qpci_config_writew(QPCIDevice *dev, uint8_t offset, uint16_t value) void qpci_config_writel(QPCIDevice *dev, uint8_t offset, uint32_t value) { - dev->bus->config_writew(dev->bus, dev->devfn, offset, value); + dev->bus->config_writel(dev->bus, dev->devfn, offset, value); } diff --git a/tests/libqtest.c b/tests/libqtest.c index 815569584..98e8f4b64 100644 --- a/tests/libqtest.c +++ b/tests/libqtest.c @@ -30,8 +30,9 @@ #include "qemu/compiler.h" #include "qemu/osdep.h" -#include "qapi/qmp/json-streamer.h" #include "qapi/qmp/json-parser.h" +#include "qapi/qmp/json-streamer.h" +#include "qapi/qmp/qjson.h" #define MAX_IRQ 256 #define SOCKET_TIMEOUT 5 @@ -72,7 +73,8 @@ static int init_socket(const char *socket_path) ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr)); } while (ret == -1 && errno == EINTR); g_assert_no_errno(ret); - listen(sock, 1); + ret = listen(sock, 1); + g_assert_no_errno(ret); return sock; } @@ -88,10 +90,13 @@ static int socket_accept(int sock) setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (void *)&timeout, sizeof(timeout)); - addrlen = sizeof(addr); do { + addrlen = sizeof(addr); ret = accept(sock, (struct sockaddr *)&addr, &addrlen); } while (ret == -1 && errno == EINTR); + if (ret == -1) { + fprintf(stderr, "%s failed: %s\n", __func__, strerror(errno)); + } close(sock); return ret; @@ -216,19 +221,15 @@ void qtest_quit(QTestState *s) g_free(s); } -static void socket_sendf(int fd, const char *fmt, va_list ap) +static void socket_send(int fd, const char *buf, size_t size) { - gchar *str; - size_t size, offset; - - str = g_strdup_vprintf(fmt, ap); - size = strlen(str); + size_t offset; offset = 0; while (offset < size) { ssize_t len; - len = write(fd, str + offset, size - offset); + len = write(fd, buf + offset, size - offset); if (len == -1 && errno == EINTR) { continue; } @@ -240,6 +241,15 @@ static void socket_sendf(int fd, const char *fmt, va_list ap) } } +static void socket_sendf(int fd, const char *fmt, va_list ap) +{ + gchar *str = g_strdup_vprintf(fmt, ap); + size_t size = strlen(str); + + socket_send(fd, str, size); + g_free(str); +} + static void GCC_FMT_ATTR(2, 3) qtest_sendf(QTestState *s, const char *fmt, ...) { va_list ap; @@ -374,8 +384,29 @@ QDict *qtest_qmp_receive(QTestState *s) QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap) { - /* Send QMP request */ - socket_sendf(s->qmp_fd, fmt, ap); + va_list ap_copy; + QObject *qobj; + + /* Going through qobject ensures we escape strings properly. + * This seemingly unnecessary copy is required in case va_list + * is an array type. + */ + va_copy(ap_copy, ap); + qobj = qobject_from_jsonv(fmt, &ap_copy); + va_end(ap_copy); + + /* No need to send anything for an empty QObject. */ + if (qobj) { + QString *qstr = qobject_to_json(qobj); + const char *str = qstring_get_str(qstr); + size_t size = qstring_get_length(qstr); + + /* Send QMP request */ + socket_send(s->qmp_fd, str, size); + + QDECREF(qstr); + qobject_decref(qobj); + } /* Receive reply */ return qtest_qmp_receive(s); diff --git a/tests/qapi-schema/duplicate-key.err b/tests/qapi-schema/duplicate-key.err index 0801c6a9b..768b276f8 100644 --- a/tests/qapi-schema/duplicate-key.err +++ b/tests/qapi-schema/duplicate-key.err @@ -1 +1 @@ -<stdin>:2:10: Duplicate key "key" +tests/qapi-schema/duplicate-key.json:2:10: Duplicate key "key" diff --git a/tests/qapi-schema/event-nest-struct.err b/tests/qapi-schema/event-nest-struct.err new file mode 100644 index 000000000..91bde1c96 --- /dev/null +++ b/tests/qapi-schema/event-nest-struct.err @@ -0,0 +1 @@ +tests/qapi-schema/event-nest-struct.json:1: Nested structure define in event is not supported, event 'EVENT_A', argname 'a' diff --git a/tests/qapi-schema/event-nest-struct.exit b/tests/qapi-schema/event-nest-struct.exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/tests/qapi-schema/event-nest-struct.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/event-nest-struct.json b/tests/qapi-schema/event-nest-struct.json new file mode 100644 index 000000000..ee6f3ecb6 --- /dev/null +++ b/tests/qapi-schema/event-nest-struct.json @@ -0,0 +1,2 @@ +{ 'event': 'EVENT_A', + 'data': { 'a' : { 'string' : 'str', 'integer': 'int' }, 'b' : 'str' } } diff --git a/tests/qapi-schema/event-nest-struct.out b/tests/qapi-schema/event-nest-struct.out new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/qapi-schema/event-nest-struct.out diff --git a/tests/qapi-schema/flat-union-invalid-branch-key.err b/tests/qapi-schema/flat-union-invalid-branch-key.err index 1125caf5d..ccf72d2df 100644 --- a/tests/qapi-schema/flat-union-invalid-branch-key.err +++ b/tests/qapi-schema/flat-union-invalid-branch-key.err @@ -1 +1 @@ -<stdin>:13: Discriminator value 'value_wrong' is not found in enum 'TestEnum' +tests/qapi-schema/flat-union-invalid-branch-key.json:13: Discriminator value 'value_wrong' is not found in enum 'TestEnum' diff --git a/tests/qapi-schema/flat-union-invalid-discriminator.err b/tests/qapi-schema/flat-union-invalid-discriminator.err index cad9dbf22..790b6759b 100644 --- a/tests/qapi-schema/flat-union-invalid-discriminator.err +++ b/tests/qapi-schema/flat-union-invalid-discriminator.err @@ -1 +1 @@ -<stdin>:13: Discriminator 'enum_wrong' is not a member of base type 'TestBase' +tests/qapi-schema/flat-union-invalid-discriminator.json:13: Discriminator 'enum_wrong' is not a member of base type 'TestBase' diff --git a/tests/qapi-schema/flat-union-no-base.err b/tests/qapi-schema/flat-union-no-base.err index e2d7443a3..a59749eb8 100644 --- a/tests/qapi-schema/flat-union-no-base.err +++ b/tests/qapi-schema/flat-union-no-base.err @@ -1 +1 @@ -<stdin>:7: Flat union 'TestUnion' must have a base field +tests/qapi-schema/flat-union-no-base.json:7: Flat union 'TestUnion' must have a base field diff --git a/tests/qapi-schema/flat-union-string-discriminator.err b/tests/qapi-schema/flat-union-string-discriminator.err index 87482704e..200016bd5 100644 --- a/tests/qapi-schema/flat-union-string-discriminator.err +++ b/tests/qapi-schema/flat-union-string-discriminator.err @@ -1 +1 @@ -<stdin>:13: Discriminator 'kind' must be of enumeration type +tests/qapi-schema/flat-union-string-discriminator.json:13: Discriminator 'kind' must be of enumeration type diff --git a/tests/qapi-schema/funny-char.err b/tests/qapi-schema/funny-char.err index d3dd293fa..bfc890cd9 100644 --- a/tests/qapi-schema/funny-char.err +++ b/tests/qapi-schema/funny-char.err @@ -1 +1 @@ -<stdin>:2:36: Stray ";" +tests/qapi-schema/funny-char.json:2:36: Stray ";" diff --git a/tests/qapi-schema/include-before-err.err b/tests/qapi-schema/include-before-err.err new file mode 100644 index 000000000..55652751e --- /dev/null +++ b/tests/qapi-schema/include-before-err.err @@ -0,0 +1 @@ +tests/qapi-schema/include-before-err.json:2:13: Expected ":" diff --git a/tests/qapi-schema/include-before-err.exit b/tests/qapi-schema/include-before-err.exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/tests/qapi-schema/include-before-err.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/include-before-err.json b/tests/qapi-schema/include-before-err.json new file mode 100644 index 000000000..afb6cb63c --- /dev/null +++ b/tests/qapi-schema/include-before-err.json @@ -0,0 +1,2 @@ +{ 'include': 'include-simple-sub.json' } +{ 'command' 'missing-colon' } diff --git a/tests/qapi-schema/include-before-err.out b/tests/qapi-schema/include-before-err.out new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/qapi-schema/include-before-err.out diff --git a/tests/qapi-schema/include-cycle-b.json b/tests/qapi-schema/include-cycle-b.json new file mode 100644 index 000000000..4fa985dcd --- /dev/null +++ b/tests/qapi-schema/include-cycle-b.json @@ -0,0 +1 @@ +{ 'include': 'include-cycle-c.json' } diff --git a/tests/qapi-schema/include-cycle-c.json b/tests/qapi-schema/include-cycle-c.json new file mode 100644 index 000000000..d12b5924a --- /dev/null +++ b/tests/qapi-schema/include-cycle-c.json @@ -0,0 +1 @@ +{ 'include': 'include-cycle.json' } diff --git a/tests/qapi-schema/include-cycle.err b/tests/qapi-schema/include-cycle.err new file mode 100644 index 000000000..602cf6232 --- /dev/null +++ b/tests/qapi-schema/include-cycle.err @@ -0,0 +1,3 @@ +In file included from tests/qapi-schema/include-cycle.json:1: +In file included from include-cycle-b.json:1: +include-cycle-c.json:1: Inclusion loop for include-cycle.json diff --git a/tests/qapi-schema/include-cycle.exit b/tests/qapi-schema/include-cycle.exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/tests/qapi-schema/include-cycle.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/include-cycle.json b/tests/qapi-schema/include-cycle.json new file mode 100644 index 000000000..6fcf1ebaa --- /dev/null +++ b/tests/qapi-schema/include-cycle.json @@ -0,0 +1 @@ +{ 'include': 'include-cycle-b.json' } diff --git a/tests/qapi-schema/include-cycle.out b/tests/qapi-schema/include-cycle.out new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/qapi-schema/include-cycle.out diff --git a/tests/qapi-schema/include-format-err.err b/tests/qapi-schema/include-format-err.err new file mode 100644 index 000000000..721ff4ecc --- /dev/null +++ b/tests/qapi-schema/include-format-err.err @@ -0,0 +1 @@ +tests/qapi-schema/include-format-err.json:1: Invalid 'include' directive diff --git a/tests/qapi-schema/include-format-err.exit b/tests/qapi-schema/include-format-err.exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/tests/qapi-schema/include-format-err.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/include-format-err.json b/tests/qapi-schema/include-format-err.json new file mode 100644 index 000000000..44980f026 --- /dev/null +++ b/tests/qapi-schema/include-format-err.json @@ -0,0 +1,2 @@ +{ 'include': 'include-simple-sub.json', + 'foo': 'bar' } diff --git a/tests/qapi-schema/include-format-err.out b/tests/qapi-schema/include-format-err.out new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/qapi-schema/include-format-err.out diff --git a/tests/qapi-schema/include-nested-err.err b/tests/qapi-schema/include-nested-err.err new file mode 100644 index 000000000..1dacbda3b --- /dev/null +++ b/tests/qapi-schema/include-nested-err.err @@ -0,0 +1,2 @@ +In file included from tests/qapi-schema/include-nested-err.json:1: +missing-colon.json:1:10: Expected ":" diff --git a/tests/qapi-schema/include-nested-err.exit b/tests/qapi-schema/include-nested-err.exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/tests/qapi-schema/include-nested-err.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/include-nested-err.json b/tests/qapi-schema/include-nested-err.json new file mode 100644 index 000000000..5631e56ea --- /dev/null +++ b/tests/qapi-schema/include-nested-err.json @@ -0,0 +1 @@ +{ 'include': 'missing-colon.json' } diff --git a/tests/qapi-schema/include-nested-err.out b/tests/qapi-schema/include-nested-err.out new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/qapi-schema/include-nested-err.out diff --git a/tests/qapi-schema/include-no-file.err b/tests/qapi-schema/include-no-file.err new file mode 100644 index 000000000..d5b9b22d8 --- /dev/null +++ b/tests/qapi-schema/include-no-file.err @@ -0,0 +1 @@ +tests/qapi-schema/include-no-file.json:1: No such file or directory: include-no-file-sub.json diff --git a/tests/qapi-schema/include-no-file.exit b/tests/qapi-schema/include-no-file.exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/tests/qapi-schema/include-no-file.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/include-no-file.json b/tests/qapi-schema/include-no-file.json new file mode 100644 index 000000000..9249ebd50 --- /dev/null +++ b/tests/qapi-schema/include-no-file.json @@ -0,0 +1 @@ +{ 'include': 'include-no-file-sub.json' } diff --git a/tests/qapi-schema/include-no-file.out b/tests/qapi-schema/include-no-file.out new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/qapi-schema/include-no-file.out diff --git a/tests/qapi-schema/include-non-file.err b/tests/qapi-schema/include-non-file.err new file mode 100644 index 000000000..9658c7880 --- /dev/null +++ b/tests/qapi-schema/include-non-file.err @@ -0,0 +1 @@ +tests/qapi-schema/include-non-file.json:1: Expected a file name (string), got: ['foo', 'bar'] diff --git a/tests/qapi-schema/include-non-file.exit b/tests/qapi-schema/include-non-file.exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/tests/qapi-schema/include-non-file.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/include-non-file.json b/tests/qapi-schema/include-non-file.json new file mode 100644 index 000000000..cd43c3f9d --- /dev/null +++ b/tests/qapi-schema/include-non-file.json @@ -0,0 +1 @@ +{ 'include': [ 'foo', 'bar' ] } diff --git a/tests/qapi-schema/include-non-file.out b/tests/qapi-schema/include-non-file.out new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/qapi-schema/include-non-file.out diff --git a/tests/qapi-schema/include-relpath-sub.json b/tests/qapi-schema/include-relpath-sub.json new file mode 100644 index 000000000..4bd4af416 --- /dev/null +++ b/tests/qapi-schema/include-relpath-sub.json @@ -0,0 +1,2 @@ +{ 'enum': 'Status', + 'data': [ 'good', 'bad', 'ugly' ] } diff --git a/tests/qapi-schema/include-relpath.err b/tests/qapi-schema/include-relpath.err new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/qapi-schema/include-relpath.err diff --git a/tests/qapi-schema/include-relpath.exit b/tests/qapi-schema/include-relpath.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/tests/qapi-schema/include-relpath.exit @@ -0,0 +1 @@ +0 diff --git a/tests/qapi-schema/include-relpath.json b/tests/qapi-schema/include-relpath.json new file mode 100644 index 000000000..05018f390 --- /dev/null +++ b/tests/qapi-schema/include-relpath.json @@ -0,0 +1 @@ +{ 'include': 'include/relpath.json' } diff --git a/tests/qapi-schema/include-relpath.out b/tests/qapi-schema/include-relpath.out new file mode 100644 index 000000000..4ce3dcf12 --- /dev/null +++ b/tests/qapi-schema/include-relpath.out @@ -0,0 +1,3 @@ +[OrderedDict([('enum', 'Status'), ('data', ['good', 'bad', 'ugly'])])] +[{'enum_name': 'Status', 'enum_values': ['good', 'bad', 'ugly']}] +[] diff --git a/tests/qapi-schema/include-repetition-sub.json b/tests/qapi-schema/include-repetition-sub.json new file mode 100644 index 000000000..6bfffdfd5 --- /dev/null +++ b/tests/qapi-schema/include-repetition-sub.json @@ -0,0 +1,2 @@ +{ 'include': 'comments.json' } +{ 'include': 'comments.json' } diff --git a/tests/qapi-schema/include-repetition.err b/tests/qapi-schema/include-repetition.err new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/qapi-schema/include-repetition.err diff --git a/tests/qapi-schema/include-repetition.exit b/tests/qapi-schema/include-repetition.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/tests/qapi-schema/include-repetition.exit @@ -0,0 +1 @@ +0 diff --git a/tests/qapi-schema/include-repetition.json b/tests/qapi-schema/include-repetition.json new file mode 100644 index 000000000..ec329dde5 --- /dev/null +++ b/tests/qapi-schema/include-repetition.json @@ -0,0 +1,3 @@ +{ 'include': 'comments.json' } +{ 'include': 'include-repetition-sub.json' } +{ 'include': 'comments.json' } diff --git a/tests/qapi-schema/include-repetition.out b/tests/qapi-schema/include-repetition.out new file mode 100644 index 000000000..4ce3dcf12 --- /dev/null +++ b/tests/qapi-schema/include-repetition.out @@ -0,0 +1,3 @@ +[OrderedDict([('enum', 'Status'), ('data', ['good', 'bad', 'ugly'])])] +[{'enum_name': 'Status', 'enum_values': ['good', 'bad', 'ugly']}] +[] diff --git a/tests/qapi-schema/include-self-cycle.err b/tests/qapi-schema/include-self-cycle.err new file mode 100644 index 000000000..981742ae5 --- /dev/null +++ b/tests/qapi-schema/include-self-cycle.err @@ -0,0 +1 @@ +tests/qapi-schema/include-self-cycle.json:1: Inclusion loop for include-self-cycle.json diff --git a/tests/qapi-schema/include-self-cycle.exit b/tests/qapi-schema/include-self-cycle.exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/tests/qapi-schema/include-self-cycle.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/include-self-cycle.json b/tests/qapi-schema/include-self-cycle.json new file mode 100644 index 000000000..55fb1b596 --- /dev/null +++ b/tests/qapi-schema/include-self-cycle.json @@ -0,0 +1 @@ +{ 'include': 'include-self-cycle.json' } diff --git a/tests/qapi-schema/include-self-cycle.out b/tests/qapi-schema/include-self-cycle.out new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/qapi-schema/include-self-cycle.out diff --git a/tests/qapi-schema/include-simple-sub.json b/tests/qapi-schema/include-simple-sub.json new file mode 100644 index 000000000..4bd4af416 --- /dev/null +++ b/tests/qapi-schema/include-simple-sub.json @@ -0,0 +1,2 @@ +{ 'enum': 'Status', + 'data': [ 'good', 'bad', 'ugly' ] } diff --git a/tests/qapi-schema/include-simple.err b/tests/qapi-schema/include-simple.err new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/qapi-schema/include-simple.err diff --git a/tests/qapi-schema/include-simple.exit b/tests/qapi-schema/include-simple.exit new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/tests/qapi-schema/include-simple.exit @@ -0,0 +1 @@ +0 diff --git a/tests/qapi-schema/include-simple.json b/tests/qapi-schema/include-simple.json new file mode 100644 index 000000000..1dd391a59 --- /dev/null +++ b/tests/qapi-schema/include-simple.json @@ -0,0 +1 @@ +{ 'include': 'include-simple-sub.json' } diff --git a/tests/qapi-schema/include-simple.out b/tests/qapi-schema/include-simple.out new file mode 100644 index 000000000..4ce3dcf12 --- /dev/null +++ b/tests/qapi-schema/include-simple.out @@ -0,0 +1,3 @@ +[OrderedDict([('enum', 'Status'), ('data', ['good', 'bad', 'ugly'])])] +[{'enum_name': 'Status', 'enum_values': ['good', 'bad', 'ugly']}] +[] diff --git a/tests/qapi-schema/include/relpath.json b/tests/qapi-schema/include/relpath.json new file mode 100644 index 000000000..45dee2470 --- /dev/null +++ b/tests/qapi-schema/include/relpath.json @@ -0,0 +1 @@ +{ 'include': '../include-relpath-sub.json' } diff --git a/tests/qapi-schema/missing-colon.err b/tests/qapi-schema/missing-colon.err index 9f2a35515..d9d66b377 100644 --- a/tests/qapi-schema/missing-colon.err +++ b/tests/qapi-schema/missing-colon.err @@ -1 +1 @@ -<stdin>:1:10: Expected ":" +tests/qapi-schema/missing-colon.json:1:10: Expected ":" diff --git a/tests/qapi-schema/missing-comma-list.err b/tests/qapi-schema/missing-comma-list.err index 4fe070019..e73d2770d 100644 --- a/tests/qapi-schema/missing-comma-list.err +++ b/tests/qapi-schema/missing-comma-list.err @@ -1 +1 @@ -<stdin>:2:20: Expected "," or "]" +tests/qapi-schema/missing-comma-list.json:2:20: Expected "," or "]" diff --git a/tests/qapi-schema/missing-comma-object.err b/tests/qapi-schema/missing-comma-object.err index b0121b5f3..52b3a8a1e 100644 --- a/tests/qapi-schema/missing-comma-object.err +++ b/tests/qapi-schema/missing-comma-object.err @@ -1 +1 @@ -<stdin>:2:3: Expected "," or "}" +tests/qapi-schema/missing-comma-object.json:2:3: Expected "," or "}" diff --git a/tests/qapi-schema/non-objects.err b/tests/qapi-schema/non-objects.err index a6c2dc26a..334f0c91a 100644 --- a/tests/qapi-schema/non-objects.err +++ b/tests/qapi-schema/non-objects.err @@ -1 +1 @@ -<stdin>:1:1: Expected "{" +tests/qapi-schema/non-objects.json:1:1: Expected "{" diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json index 818c06dc7..ab4d3d96b 100644 --- a/tests/qapi-schema/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -89,3 +89,15 @@ '*u16' : [ 'uint16' ], '*i64x': 'int' , '*u64x': 'uint64' } } + +# testing event +{ 'type': 'EventStructOne', + 'data': { 'struct1': 'UserDefOne', 'string': 'str', '*enum2': 'EnumOne' } } + +{ 'event': 'EVENT_A' } +{ 'event': 'EVENT_B', + 'data': { } } +{ 'event': 'EVENT_C', + 'data': { '*a': 'int', '*b': 'UserDefOne', 'c': 'str' } } +{ 'event': 'EVENT_D', + 'data': { 'a' : 'EventStructOne', 'b' : 'str', '*c': 'str', '*enum3': 'EnumOne' } } diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out index 6cd03f31c..95e989925 100644 --- a/tests/qapi-schema/qapi-schema-test.out +++ b/tests/qapi-schema/qapi-schema-test.out @@ -15,7 +15,12 @@ OrderedDict([('command', 'user_def_cmd1'), ('data', OrderedDict([('ud1a', 'UserDefOne')]))]), OrderedDict([('command', 'user_def_cmd2'), ('data', OrderedDict([('ud1a', 'UserDefOne'), ('*ud1b', 'UserDefOne')])), ('returns', 'UserDefTwo')]), OrderedDict([('command', 'user_def_cmd3'), ('data', OrderedDict([('a', 'int'), ('*b', 'int')])), ('returns', 'int')]), - OrderedDict([('type', 'UserDefOptions'), ('data', OrderedDict([('*i64', ['int']), ('*u64', ['uint64']), ('*u16', ['uint16']), ('*i64x', 'int'), ('*u64x', 'uint64')]))])] + OrderedDict([('type', 'UserDefOptions'), ('data', OrderedDict([('*i64', ['int']), ('*u64', ['uint64']), ('*u16', ['uint16']), ('*i64x', 'int'), ('*u64x', 'uint64')]))]), + OrderedDict([('type', 'EventStructOne'), ('data', OrderedDict([('struct1', 'UserDefOne'), ('string', 'str'), ('*enum2', 'EnumOne')]))]), + OrderedDict([('event', 'EVENT_A')]), + OrderedDict([('event', 'EVENT_B'), ('data', OrderedDict())]), + OrderedDict([('event', 'EVENT_C'), ('data', OrderedDict([('*a', 'int'), ('*b', 'UserDefOne'), ('c', 'str')]))]), + OrderedDict([('event', 'EVENT_D'), ('data', OrderedDict([('a', 'EventStructOne'), ('b', 'str'), ('*c', 'str'), ('*enum3', 'EnumOne')]))])] [{'enum_name': 'EnumOne', 'enum_values': ['value1', 'value2', 'value3']}, {'enum_name': 'UserDefUnionKind', 'enum_values': None}, {'enum_name': 'UserDefAnonUnionKind', 'enum_values': None}, @@ -28,4 +33,5 @@ OrderedDict([('type', 'UserDefA'), ('data', OrderedDict([('boolean', 'bool')]))]), OrderedDict([('type', 'UserDefB'), ('data', OrderedDict([('integer', 'int')]))]), OrderedDict([('type', 'UserDefUnionBase'), ('data', OrderedDict([('string', 'str'), ('enum1', 'EnumOne')]))]), - OrderedDict([('type', 'UserDefOptions'), ('data', OrderedDict([('*i64', ['int']), ('*u64', ['uint64']), ('*u16', ['uint16']), ('*i64x', 'int'), ('*u64x', 'uint64')]))])] + OrderedDict([('type', 'UserDefOptions'), ('data', OrderedDict([('*i64', ['int']), ('*u64', ['uint64']), ('*u16', ['uint16']), ('*i64x', 'int'), ('*u64x', 'uint64')]))]), + OrderedDict([('type', 'EventStructOne'), ('data', OrderedDict([('struct1', 'UserDefOne'), ('string', 'str'), ('*enum2', 'EnumOne')]))])] diff --git a/tests/qapi-schema/quoted-structural-chars.err b/tests/qapi-schema/quoted-structural-chars.err index a6c2dc26a..9b183841d 100644 --- a/tests/qapi-schema/quoted-structural-chars.err +++ b/tests/qapi-schema/quoted-structural-chars.err @@ -1 +1 @@ -<stdin>:1:1: Expected "{" +tests/qapi-schema/quoted-structural-chars.json:1:1: Expected "{" diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py index b3d1e1dbc..634ef2d00 100644 --- a/tests/qapi-schema/test-qapi.py +++ b/tests/qapi-schema/test-qapi.py @@ -12,15 +12,13 @@ from qapi import * from pprint import pprint +import os import sys try: - exprs = parse_schema(sys.stdin) + exprs = parse_schema(sys.argv[1]) except SystemExit: raise -except: - print >>sys.stderr, "Crashed:", sys.exc_info()[0] - exit(1) pprint(exprs) pprint(enum_types) diff --git a/tests/qapi-schema/trailing-comma-list.err b/tests/qapi-schema/trailing-comma-list.err index ff839a34e..24c24b010 100644 --- a/tests/qapi-schema/trailing-comma-list.err +++ b/tests/qapi-schema/trailing-comma-list.err @@ -1 +1 @@ -<stdin>:2:36: Expected "{", "[" or string +tests/qapi-schema/trailing-comma-list.json:2:36: Expected "{", "[" or string diff --git a/tests/qapi-schema/trailing-comma-object.err b/tests/qapi-schema/trailing-comma-object.err index f5409627d..30bce5e19 100644 --- a/tests/qapi-schema/trailing-comma-object.err +++ b/tests/qapi-schema/trailing-comma-object.err @@ -1 +1 @@ -<stdin>:2:38: Expected string +tests/qapi-schema/trailing-comma-object.json:2:38: Expected string diff --git a/tests/qapi-schema/unclosed-list.err b/tests/qapi-schema/unclosed-list.err index 0e837a7fa..fb41a86ab 100644 --- a/tests/qapi-schema/unclosed-list.err +++ b/tests/qapi-schema/unclosed-list.err @@ -1 +1 @@ -<stdin>:1:20: Expected "," or "]" +tests/qapi-schema/unclosed-list.json:1:20: Expected "," or "]" diff --git a/tests/qapi-schema/unclosed-object.err b/tests/qapi-schema/unclosed-object.err index e6dc9501d..db3deedd6 100644 --- a/tests/qapi-schema/unclosed-object.err +++ b/tests/qapi-schema/unclosed-object.err @@ -1 +1 @@ -<stdin>:1:21: Expected "," or "}" +tests/qapi-schema/unclosed-object.json:1:21: Expected "," or "}" diff --git a/tests/qapi-schema/unclosed-string.err b/tests/qapi-schema/unclosed-string.err index 948d88339..12b187074 100644 --- a/tests/qapi-schema/unclosed-string.err +++ b/tests/qapi-schema/unclosed-string.err @@ -1 +1 @@ -<stdin>:1:11: Missing terminating "'" +tests/qapi-schema/unclosed-string.json:1:11: Missing terminating "'" diff --git a/tests/qapi-schema/union-invalid-base.err b/tests/qapi-schema/union-invalid-base.err index dd8e3d1b3..938f96962 100644 --- a/tests/qapi-schema/union-invalid-base.err +++ b/tests/qapi-schema/union-invalid-base.err @@ -1 +1 @@ -<stdin>:7: Base 'TestBaseWrong' is not a valid type +tests/qapi-schema/union-invalid-base.json:7: Base 'TestBaseWrong' is not a valid type diff --git a/tests/qemu-iotests-quick.sh b/tests/qemu-iotests-quick.sh index c449e8ab4..8a9a4c68e 100755 --- a/tests/qemu-iotests-quick.sh +++ b/tests/qemu-iotests-quick.sh @@ -1,16 +1,6 @@ #!/bin/sh -# We don't know which of the system emulator binaries there is (or if there is -# any at all), so the 'quick' group doesn't contain any tests that require -# running qemu proper. Assign a fake binary name so that qemu-iotests doesn't -# complain about the missing binary. -export QEMU_PROG="this_should_be_unused" - -export QEMU_IMG_PROG="$(pwd)/qemu-img" -export QEMU_IO_PROG="$(pwd)/qemu-io" -export QEMU_NBD_PROG="$(pwd)/qemu-nbd" - -cd $SRC_PATH/tests/qemu-iotests +cd tests/qemu-iotests ret=0 ./check -T -nocache -qcow2 -g quick || ret=1 diff --git a/tests/qemu-iotests/019 b/tests/qemu-iotests/019 index e67445c75..f5ecbf545 100755 --- a/tests/qemu-iotests/019 +++ b/tests/qemu-iotests/019 @@ -96,7 +96,7 @@ mv "$TEST_IMG" "$TEST_IMG.orig" for backing_option in "-B " "-o backing_file="; do echo - echo Testing conversion with $backing_option$TEST_IMG.base | _filter_testdir | _filter_imgfmt + echo Testing conversion with $backing_option"$TEST_IMG.base" | _filter_testdir | _filter_imgfmt echo $QEMU_IMG convert -O $IMGFMT $backing_option"$TEST_IMG.base" "$TEST_IMG.orig" "$TEST_IMG" diff --git a/tests/qemu-iotests/028 b/tests/qemu-iotests/028 index a99e4fa2b..9e701e1c2 100755 --- a/tests/qemu-iotests/028 +++ b/tests/qemu-iotests/028 @@ -33,7 +33,8 @@ status=1 # failure is the default! _cleanup() { - _cleanup_test_img + rm -f "${TEST_IMG}.copy" + _cleanup_test_img } trap "_cleanup; exit \$status" 0 1 2 3 15 @@ -41,6 +42,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 . ./common.rc . ./common.filter . ./common.pattern +. ./common.qemu # Any format supporting backing files except vmdk and qcow which do not support # smaller backing files. @@ -99,6 +101,31 @@ _check_test_img # Rebase it on top of its base image $QEMU_IMG rebase -b "$TEST_IMG.base" "$TEST_IMG" +echo +echo block-backup +echo + +qemu_comm_method="monitor" +_launch_qemu -drive file="${TEST_IMG}",cache=${CACHEMODE},id=disk +h=$QEMU_HANDLE +QEMU_COMM_TIMEOUT=1 + +# Silence output since it contains the disk image path and QEMU's readline +# character echoing makes it very hard to filter the output +_send_qemu_cmd $h "drive_backup disk ${TEST_IMG}.copy" "(qemu)" >/dev/null +qemu_cmd_repeat=20 _send_qemu_cmd $h "info block-jobs" "No active jobs" +_send_qemu_cmd $h 'quit' "" + +# Base image sectors +TEST_IMG="${TEST_IMG}.copy" io readv $(( offset )) 512 1024 32 + +# Image sectors +TEST_IMG="${TEST_IMG}.copy" io readv $(( offset + 512 )) 512 1024 64 + +# Zero sectors beyond end of base image +TEST_IMG="${TEST_IMG}.copy" io_zero readv $(( offset + 32 * 1024 )) 512 1024 32 + + _check_test_img # success, all done diff --git a/tests/qemu-iotests/028.out b/tests/qemu-iotests/028.out index 8affb7f3a..0e1a5ae65 100644 --- a/tests/qemu-iotests/028.out +++ b/tests/qemu-iotests/028.out @@ -465,5 +465,272 @@ read 512/512 bytes at offset 3221257728 read 512/512 bytes at offset 3221258752 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) No errors were found on the image. + +block-backup + +Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=4294968832 backing_file='TEST_DIR/t.qcow2.base' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off +(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block-[K[D[D[D[D[D[D[D[D[D[D[Dinfo block-j[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block-jo[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block-job[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block-jobs[K +Type backup, device disk: Completed 0 of 4294968832 bytes, speed limit 0 bytes/s +i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block-[K[D[D[D[D[D[D[D[D[D[D[Dinfo block-j[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block-jo[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block-job[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block-jobs[K +No active jobs +=== IO: pattern 195 +read 512/512 bytes at offset 3221194240 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221195264 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221196288 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221197312 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221198336 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221199360 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221200384 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221201408 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221202432 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221203456 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221204480 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221205504 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221206528 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221207552 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221208576 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221209600 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221210624 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221211648 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221212672 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221213696 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221214720 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221215744 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221216768 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221217792 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221218816 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221219840 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221220864 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221221888 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221222912 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221223936 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221224960 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221225984 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +=== IO: pattern 196 +read 512/512 bytes at offset 3221194752 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221195776 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221196800 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221197824 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221198848 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221199872 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221200896 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221201920 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221202944 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221203968 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221204992 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221206016 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221207040 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221208064 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221209088 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221210112 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221211136 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221212160 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221213184 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221214208 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221215232 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221216256 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221217280 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221218304 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221219328 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221220352 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221221376 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221222400 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221223424 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221224448 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221225472 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221226496 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221227520 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221228544 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221229568 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221230592 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221231616 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221232640 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221233664 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221234688 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221235712 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221236736 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221237760 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221238784 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221239808 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221240832 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221241856 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221242880 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221243904 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221244928 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221245952 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221246976 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221248000 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221249024 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221250048 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221251072 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221252096 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221253120 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221254144 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221255168 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221256192 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221257216 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221258240 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221259264 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +=== IO: pattern 0 +read 512/512 bytes at offset 3221227008 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221228032 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221229056 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221230080 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221231104 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221232128 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221233152 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221234176 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221235200 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221236224 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221237248 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221238272 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221239296 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221240320 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221241344 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221242368 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221243392 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221244416 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221245440 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221246464 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221247488 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221248512 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221249536 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221250560 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221251584 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221252608 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221253632 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221254656 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221255680 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221256704 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221257728 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 3221258752 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) No errors were found on the image. *** done diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030 index 59a34f76f..8ce2373cf 100755 --- a/tests/qemu-iotests/030 +++ b/tests/qemu-iotests/030 @@ -35,7 +35,7 @@ class TestSingleDrive(iotests.QMPTestCase): qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, mid_img) qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img) qemu_io('-c', 'write -P 0x1 0 512', backing_img) - self.vm = iotests.VM().add_drive(test_img) + self.vm = iotests.VM().add_drive("blkdebug::" + test_img) self.vm.launch() def tearDown(self): @@ -50,15 +50,7 @@ class TestSingleDrive(iotests.QMPTestCase): result = self.vm.qmp('block-stream', device='drive0') self.assert_qmp(result, 'return', {}) - completed = False - while not completed: - for event in self.vm.get_qmp_events(wait=True): - if event['event'] == 'BLOCK_JOB_COMPLETED': - self.assert_qmp(event, 'data/type', 'stream') - self.assert_qmp(event, 'data/device', 'drive0') - self.assert_qmp(event, 'data/offset', self.image_len) - self.assert_qmp(event, 'data/len', self.image_len) - completed = True + self.wait_until_completed() self.assert_no_active_block_jobs() self.vm.shutdown() @@ -89,15 +81,7 @@ class TestSingleDrive(iotests.QMPTestCase): self.assert_qmp(result, 'return', {}) self.vm.resume_drive('drive0') - completed = False - while not completed: - for event in self.vm.get_qmp_events(wait=True): - if event['event'] == 'BLOCK_JOB_COMPLETED': - self.assert_qmp(event, 'data/type', 'stream') - self.assert_qmp(event, 'data/device', 'drive0') - self.assert_qmp(event, 'data/offset', self.image_len) - self.assert_qmp(event, 'data/len', self.image_len) - completed = True + self.wait_until_completed() self.assert_no_active_block_jobs() self.vm.shutdown() @@ -112,15 +96,7 @@ class TestSingleDrive(iotests.QMPTestCase): result = self.vm.qmp('block-stream', device='drive0', base=mid_img) self.assert_qmp(result, 'return', {}) - completed = False - while not completed: - for event in self.vm.get_qmp_events(wait=True): - if event['event'] == 'BLOCK_JOB_COMPLETED': - self.assert_qmp(event, 'data/type', 'stream') - self.assert_qmp(event, 'data/device', 'drive0') - self.assert_qmp(event, 'data/offset', self.image_len) - self.assert_qmp(event, 'data/len', self.image_len) - completed = True + self.wait_until_completed() self.assert_no_active_block_jobs() self.vm.shutdown() @@ -152,15 +128,7 @@ class TestSmallerBackingFile(iotests.QMPTestCase): result = self.vm.qmp('block-stream', device='drive0') self.assert_qmp(result, 'return', {}) - completed = False - while not completed: - for event in self.vm.get_qmp_events(wait=True): - if event['event'] == 'BLOCK_JOB_COMPLETED': - self.assert_qmp(event, 'data/type', 'stream') - self.assert_qmp(event, 'data/device', 'drive0') - self.assert_qmp(event, 'data/offset', self.image_len) - self.assert_qmp(event, 'data/len', self.image_len) - completed = True + self.wait_until_completed() self.assert_no_active_block_jobs() self.vm.shutdown() @@ -442,15 +410,7 @@ class TestSetSpeed(iotests.QMPTestCase): result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024) self.assert_qmp(result, 'return', {}) - completed = False - while not completed: - for event in self.vm.get_qmp_events(wait=True): - if event['event'] == 'BLOCK_JOB_COMPLETED': - self.assert_qmp(event, 'data/type', 'stream') - self.assert_qmp(event, 'data/device', 'drive0') - self.assert_qmp(event, 'data/offset', self.image_len) - self.assert_qmp(event, 'data/len', self.image_len) - completed = True + self.wait_until_completed() self.assert_no_active_block_jobs() diff --git a/tests/qemu-iotests/031 b/tests/qemu-iotests/031 index 1d920ea87..2a77ba8cb 100755 --- a/tests/qemu-iotests/031 +++ b/tests/qemu-iotests/031 @@ -56,22 +56,22 @@ for IMGOPTS in "compat=0.10" "compat=1.1"; do echo === Create image with unknown header extension === echo _make_test_img 64M - ./qcow2.py "$TEST_IMG" add-header-ext 0x12345678 "This is a test header extension" - ./qcow2.py "$TEST_IMG" dump-header + $PYTHON qcow2.py "$TEST_IMG" add-header-ext 0x12345678 "This is a test header extension" + $PYTHON qcow2.py "$TEST_IMG" dump-header _check_test_img echo echo === Rewrite header with no backing file === echo $QEMU_IMG rebase -u -b "" "$TEST_IMG" - ./qcow2.py "$TEST_IMG" dump-header + $PYTHON qcow2.py "$TEST_IMG" dump-header _check_test_img echo echo === Add a backing file and format === echo $QEMU_IMG rebase -u -b "/some/backing/file/path" -F host_device "$TEST_IMG" - ./qcow2.py "$TEST_IMG" dump-header + $PYTHON qcow2.py "$TEST_IMG" dump-header done # success, all done diff --git a/tests/qemu-iotests/036 b/tests/qemu-iotests/036 index 03b6aa9de..392f1ef3e 100755 --- a/tests/qemu-iotests/036 +++ b/tests/qemu-iotests/036 @@ -1,6 +1,6 @@ #!/bin/bash # -# Test that qcow2 unknown autoclear feature bits are cleared +# Test qcow2 feature bits # # Copyright (C) 2011 Red Hat, Inc. # Copyright IBM, Corp. 2010 @@ -50,18 +50,68 @@ _supported_os Linux # Only qcow2v3 and later supports feature bits IMGOPTS="compat=1.1" +echo +echo === Image with unknown incompatible feature bit === +echo +_make_test_img 64M +$PYTHON qcow2.py "$TEST_IMG" set-feature-bit incompatible 63 + +# Without feature table +$PYTHON qcow2.py "$TEST_IMG" dump-header +_img_info + +# With feature table containing bit 63 +printf "\x00\x3f%s" "Test feature" | $PYTHON qcow2.py "$TEST_IMG" add-header-ext-stdio 0x6803f857 +_img_info + +echo +echo === Image with multiple incompatible feature bits === +echo +_make_test_img 64M +$PYTHON qcow2.py "$TEST_IMG" set-feature-bit incompatible 61 +$PYTHON qcow2.py "$TEST_IMG" set-feature-bit incompatible 62 +$PYTHON qcow2.py "$TEST_IMG" set-feature-bit incompatible 63 + +# Without feature table +_img_info + +# With feature table containing bit 63 +printf "\x00\x3f%s" "Test feature" | $PYTHON qcow2.py "$TEST_IMG" add-header-ext-stdio 0x6803f857 +_img_info + +# With feature table containing bit 61 +$PYTHON qcow2.py "$TEST_IMG" del-header-ext 0x6803f857 +printf "\x00\x3d%s" "Test feature" | $PYTHON qcow2.py "$TEST_IMG" add-header-ext-stdio 0x6803f857 +_img_info + +# With feature table containing bits 61 and 62 +$PYTHON qcow2.py "$TEST_IMG" del-header-ext 0x6803f857 +printf "\x00\x3d%s\x00%40s\x00\x3e%s\x00%40s" "test1" "" "test2" "" | $PYTHON qcow2.py "$TEST_IMG" add-header-ext-stdio 0x6803f857 +_img_info + +# With feature table containing all bits +$PYTHON qcow2.py "$TEST_IMG" del-header-ext 0x6803f857 +printf "\x00\x3d%s\x00%40s\x00\x3e%s\x00%40s\x00\x3f%s\x00%40s" "test1" "" "test2" "" "test3" "" | $PYTHON qcow2.py "$TEST_IMG" add-header-ext-stdio 0x6803f857 +_img_info + +# With feature table containing unrelated bits, including compatible/autoclear +$PYTHON qcow2.py "$TEST_IMG" del-header-ext 0x6803f857 +printf "\x01\x3d%s\x00%40s\x00\x3e%s\x00%40s\x02\x3f%s\x00%40s\x00\x3c%s\x00%40s" "test1" "" "test2" "" "test3" "" "test4" "" | $PYTHON qcow2.py "$TEST_IMG" add-header-ext-stdio 0x6803f857 +_img_info + + echo === Create image with unknown autoclear feature bit === echo _make_test_img 64M -./qcow2.py "$TEST_IMG" set-feature-bit autoclear 63 -./qcow2.py "$TEST_IMG" dump-header +$PYTHON qcow2.py "$TEST_IMG" set-feature-bit autoclear 63 +$PYTHON qcow2.py "$TEST_IMG" dump-header echo echo === Repair image === echo _check_test_img -r all -./qcow2.py "$TEST_IMG" dump-header +$PYTHON qcow2.py "$TEST_IMG" dump-header # success, all done echo "*** done" diff --git a/tests/qemu-iotests/036.out b/tests/qemu-iotests/036.out index 55a3e6e44..720bd8916 100644 --- a/tests/qemu-iotests/036.out +++ b/tests/qemu-iotests/036.out @@ -1,4 +1,39 @@ QA output created by 036 + +=== Image with unknown incompatible feature bit === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +magic 0x514649fb +version 3 +backing_file_offset 0x0 +backing_file_size 0x0 +cluster_bits 16 +size 67108864 +crypt_method 0 +l1_size 1 +l1_table_offset 0x30000 +refcount_table_offset 0x10000 +refcount_table_clusters 1 +nb_snapshots 0 +snapshot_offset 0x0 +incompatible_features 0x8000000000000000 +compatible_features 0x0 +autoclear_features 0x0 +refcount_order 4 +header_length 104 + +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: Unknown incompatible feature: 8000000000000000 +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: Test feature + +=== Image with multiple incompatible feature bits === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: Unknown incompatible feature: e000000000000000 +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: Test feature, Unknown incompatible feature: 6000000000000000 +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: Test feature, Unknown incompatible feature: c000000000000000 +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: test1, test2, Unknown incompatible feature: 8000000000000000 +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: test1, test2, test3 +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: test2, Unknown incompatible feature: a000000000000000 === Create image with unknown autoclear feature bit === Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 diff --git a/tests/qemu-iotests/039 b/tests/qemu-iotests/039 index b9cbe9956..84c916766 100755 --- a/tests/qemu-iotests/039 +++ b/tests/qemu-iotests/039 @@ -47,6 +47,11 @@ _supported_os Linux _default_cache_mode "writethrough" _supported_cache_modes "writethrough" +_no_dump_exec() +{ + (ulimit -c 0; exec "$@") +} + size=128M echo @@ -58,7 +63,7 @@ _make_test_img $size $QEMU_IO -c "write -P 0x5a 0 512" "$TEST_IMG" | _filter_qemu_io # The dirty bit must not be set -./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features _check_test_img echo @@ -67,13 +72,10 @@ echo "== Creating a dirty image file ==" IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img $size -old_ulimit=$(ulimit -c) -ulimit -c 0 # do not produce a core dump on abort(3) -$QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" | _filter_qemu_io -ulimit -c "$old_ulimit" +_no_dump_exec $QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" 2>&1 | _filter_qemu_io # The dirty bit must be set -./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features _check_test_img echo @@ -82,7 +84,7 @@ echo "== Read-only access must still work ==" $QEMU_IO -r -c "read -P 0x5a 0 512" "$TEST_IMG" | _filter_qemu_io # The dirty bit must be set -./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features echo echo "== Repairing the image file must succeed ==" @@ -90,7 +92,7 @@ echo "== Repairing the image file must succeed ==" _check_test_img -r all # The dirty bit must not be set -./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features echo echo "== Data should still be accessible after repair ==" @@ -103,18 +105,15 @@ echo "== Opening a dirty image read/write should repair it ==" IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img $size -old_ulimit=$(ulimit -c) -ulimit -c 0 # do not produce a core dump on abort(3) -$QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" | _filter_qemu_io -ulimit -c "$old_ulimit" +_no_dump_exec $QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" 2>&1 | _filter_qemu_io # The dirty bit must be set -./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features $QEMU_IO -c "write 0 512" "$TEST_IMG" | _filter_qemu_io # The dirty bit must not be set -./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features echo echo "== Creating an image file with lazy_refcounts=off ==" @@ -122,13 +121,10 @@ echo "== Creating an image file with lazy_refcounts=off ==" IMGOPTS="compat=1.1,lazy_refcounts=off" _make_test_img $size -old_ulimit=$(ulimit -c) -ulimit -c 0 # do not produce a core dump on abort(3) -$QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" | _filter_qemu_io -ulimit -c "$old_ulimit" +_no_dump_exec $QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" 2>&1 | _filter_qemu_io # The dirty bit must not be set since lazy_refcounts=off -./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features _check_test_img echo @@ -144,8 +140,8 @@ $QEMU_IO -c "write 0 512" "$TEST_IMG" | _filter_qemu_io $QEMU_IMG commit "$TEST_IMG" # The dirty bit must not be set -./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features -./qcow2.py "$TEST_IMG".base dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG".base dump-header | grep incompatible_features _check_test_img TEST_IMG="$TEST_IMG".base _check_test_img diff --git a/tests/qemu-iotests/039.out b/tests/qemu-iotests/039.out index fb31ae062..67e774430 100644 --- a/tests/qemu-iotests/039.out +++ b/tests/qemu-iotests/039.out @@ -11,6 +11,7 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 wrote 512/512 bytes at offset 0 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +./039: Aborted ( ulimit -c 0; exec "$@" ) incompatible_features 0x1 ERROR cluster 5 refcount=0 reference=1 ERROR OFLAG_COPIED data cluster: l2_entry=8000000000050000 refcount=0 @@ -42,6 +43,7 @@ read 512/512 bytes at offset 0 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 wrote 512/512 bytes at offset 0 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +./039: Aborted ( ulimit -c 0; exec "$@" ) incompatible_features 0x1 Repairing cluster 5 refcount=0 reference=1 wrote 512/512 bytes at offset 0 @@ -52,6 +54,7 @@ incompatible_features 0x0 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 wrote 512/512 bytes at offset 0 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +./039: Aborted ( ulimit -c 0; exec "$@" ) incompatible_features 0x0 No errors were found on the image. diff --git a/tests/qemu-iotests/040 b/tests/qemu-iotests/040 index 734b6a6bb..f1e16c11c 100755 --- a/tests/qemu-iotests/040 +++ b/tests/qemu-iotests/040 @@ -35,12 +35,9 @@ test_img = os.path.join(iotests.test_dir, 'test.img') class ImageCommitTestCase(iotests.QMPTestCase): '''Abstract base class for image commit test cases''' - def run_commit_test(self, top, base): - self.assert_no_active_block_jobs() - result = self.vm.qmp('block-commit', device='drive0', top=top, base=base) - self.assert_qmp(result, 'return', {}) - + def wait_for_complete(self, need_ready=False): completed = False + ready = False while not completed: for event in self.vm.get_qmp_events(wait=True): if event['event'] == 'BLOCK_JOB_COMPLETED': @@ -48,8 +45,11 @@ class ImageCommitTestCase(iotests.QMPTestCase): self.assert_qmp(event, 'data/device', 'drive0') self.assert_qmp(event, 'data/offset', self.image_len) self.assert_qmp(event, 'data/len', self.image_len) + if need_ready: + self.assertTrue(ready, "Expecting BLOCK_JOB_COMPLETED event") completed = True elif event['event'] == 'BLOCK_JOB_READY': + ready = True self.assert_qmp(event, 'data/type', 'commit') self.assert_qmp(event, 'data/device', 'drive0') self.assert_qmp(event, 'data/len', self.image_len) @@ -58,12 +58,24 @@ class ImageCommitTestCase(iotests.QMPTestCase): self.assert_no_active_block_jobs() self.vm.shutdown() + def run_commit_test(self, top, base, need_ready=False): + self.assert_no_active_block_jobs() + result = self.vm.qmp('block-commit', device='drive0', top=top, base=base) + self.assert_qmp(result, 'return', {}) + self.wait_for_complete(need_ready) + + def run_default_commit_test(self): + self.assert_no_active_block_jobs() + result = self.vm.qmp('block-commit', device='drive0') + self.assert_qmp(result, 'return', {}) + self.wait_for_complete() + class TestSingleDrive(ImageCommitTestCase): image_len = 1 * 1024 * 1024 test_len = 1 * 1024 * 256 def setUp(self): - iotests.create_image(backing_img, TestSingleDrive.image_len) + iotests.create_image(backing_img, self.image_len) qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, mid_img) qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img) qemu_io('-c', 'write -P 0xab 0 524288', backing_img) @@ -105,7 +117,12 @@ class TestSingleDrive(ImageCommitTestCase): self.assert_qmp(result, 'error/desc', 'Base \'badfile\' not found') def test_top_is_active(self): - self.run_commit_test(test_img, backing_img) + self.run_commit_test(test_img, backing_img, need_ready=True) + self.assertEqual(-1, qemu_io('-c', 'read -P 0xab 0 524288', backing_img).find("verification failed")) + self.assertEqual(-1, qemu_io('-c', 'read -P 0xef 524288 524288', backing_img).find("verification failed")) + + def test_top_is_default_active(self): + self.run_default_commit_test() self.assertEqual(-1, qemu_io('-c', 'read -P 0xab 0 524288', backing_img).find("verification failed")) self.assertEqual(-1, qemu_io('-c', 'read -P 0xef 524288 524288', backing_img).find("verification failed")) @@ -115,11 +132,6 @@ class TestSingleDrive(ImageCommitTestCase): self.assert_qmp(result, 'error/class', 'GenericError') self.assert_qmp(result, 'error/desc', 'Base \'%s\' not found' % mid_img) - def test_top_omitted(self): - self.assert_no_active_block_jobs() - result = self.vm.qmp('block-commit', device='drive0') - self.assert_qmp(result, 'error/class', 'GenericError') - self.assert_qmp(result, 'error/desc', "Parameter 'top' is missing") class TestRelativePaths(ImageCommitTestCase): image_len = 1 * 1024 * 1024 @@ -238,6 +250,8 @@ class TestSetSpeed(ImageCommitTestCase): self.cancel_and_wait(resume=True) +class TestActiveZeroLengthImage(TestSingleDrive): + image_len = 0 if __name__ == '__main__': iotests.main(supported_fmts=['qcow2', 'qed']) diff --git a/tests/qemu-iotests/040.out b/tests/qemu-iotests/040.out index b6f257674..42314e9c0 100644 --- a/tests/qemu-iotests/040.out +++ b/tests/qemu-iotests/040.out @@ -1,5 +1,5 @@ -................ +........................ ---------------------------------------------------------------------- -Ran 16 tests +Ran 24 tests OK diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041 index ec470b200..5dbd4ee91 100755 --- a/tests/qemu-iotests/041 +++ b/tests/qemu-iotests/041 @@ -28,6 +28,12 @@ target_backing_img = os.path.join(iotests.test_dir, 'target-backing.img') test_img = os.path.join(iotests.test_dir, 'test.img') target_img = os.path.join(iotests.test_dir, 'target.img') +quorum_img1 = os.path.join(iotests.test_dir, 'quorum1.img') +quorum_img2 = os.path.join(iotests.test_dir, 'quorum2.img') +quorum_img3 = os.path.join(iotests.test_dir, 'quorum3.img') +quorum_repair_img = os.path.join(iotests.test_dir, 'quorum_repair.img') +quorum_snapshot_file = os.path.join(iotests.test_dir, 'quorum_snapshot.img') + class ImageMirroringTestCase(iotests.QMPTestCase): '''Abstract base class for image mirroring test cases''' @@ -42,8 +48,8 @@ class ImageMirroringTestCase(iotests.QMPTestCase): ready = True def wait_ready_and_cancel(self, drive='drive0'): - self.wait_ready(drive) - event = self.cancel_and_wait() + self.wait_ready(drive=drive) + event = self.cancel_and_wait(drive=drive) self.assertEquals(event['event'], 'BLOCK_JOB_COMPLETED') self.assert_qmp(event, 'data/type', 'mirror') self.assert_qmp(event, 'data/offset', self.image_len) @@ -52,19 +58,19 @@ class ImageMirroringTestCase(iotests.QMPTestCase): def complete_and_wait(self, drive='drive0', wait_ready=True): '''Complete a block job and wait for it to finish''' if wait_ready: - self.wait_ready() + self.wait_ready(drive=drive) result = self.vm.qmp('block-job-complete', device=drive) self.assert_qmp(result, 'return', {}) - event = self.wait_until_completed() + event = self.wait_until_completed(drive=drive) self.assert_qmp(event, 'data/type', 'mirror') class TestSingleDrive(ImageMirroringTestCase): image_len = 1 * 1024 * 1024 # MB def setUp(self): - iotests.create_image(backing_img, TestSingleDrive.image_len) + iotests.create_image(backing_img, self.image_len) qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) self.vm = iotests.VM().add_drive(test_img) self.vm.launch() @@ -163,7 +169,7 @@ class TestSingleDrive(ImageMirroringTestCase): self.assert_no_active_block_jobs() qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,size=%d' - % (TestSingleDrive.image_len, TestSingleDrive.image_len), target_img) + % (self.image_len, self.image_len), target_img) result = self.vm.qmp('drive-mirror', device='drive0', sync='full', buf_size=65536, mode='existing', target=target_img) self.assert_qmp(result, 'return', {}) @@ -179,7 +185,7 @@ class TestSingleDrive(ImageMirroringTestCase): self.assert_no_active_block_jobs() qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,backing_file=%s' - % (TestSingleDrive.image_len, backing_img), target_img) + % (self.image_len, backing_img), target_img) result = self.vm.qmp('drive-mirror', device='drive0', sync='full', mode='existing', target=target_img) self.assert_qmp(result, 'return', {}) @@ -206,6 +212,16 @@ class TestSingleDrive(ImageMirroringTestCase): target=target_img) self.assert_qmp(result, 'error/class', 'DeviceNotFound') +class TestSingleDriveZeroLength(TestSingleDrive): + image_len = 0 + test_small_buffer2 = None + test_large_cluster = None + +class TestSingleDriveUnalignedLength(TestSingleDrive): + image_len = 1025 * 1024 + test_small_buffer2 = None + test_large_cluster = None + class TestMirrorNoBacking(ImageMirroringTestCase): image_len = 2 * 1024 * 1024 # MB @@ -718,5 +734,224 @@ class TestUnbackedSource(ImageMirroringTestCase): self.complete_and_wait() self.assert_no_active_block_jobs() +class TestRepairQuorum(ImageMirroringTestCase): + """ This class test quorum file repair using drive-mirror. + It's mostly a fork of TestSingleDrive """ + image_len = 1 * 1024 * 1024 # MB + IMAGES = [ quorum_img1, quorum_img2, quorum_img3 ] + + def has_quorum(self): + return 'quorum' in iotests.qemu_img_pipe('--help') + + def setUp(self): + self.vm = iotests.VM() + + # Add each individual quorum images + for i in self.IMAGES: + qemu_img('create', '-f', iotests.imgfmt, i, + str(TestSingleDrive.image_len)) + # Assign a node name to each quorum image in order to manipulate + # them + opts = "node-name=img%i" % self.IMAGES.index(i) + self.vm = self.vm.add_drive(i, opts) + + self.vm.launch() + + #assemble the quorum block device from the individual files + args = { "options" : { "driver": "quorum", "id": "quorum0", + "vote-threshold": 2, "children": [ "img0", "img1", "img2" ] } } + if self.has_quorum(): + result = self.vm.qmp("blockdev-add", **args) + self.assert_qmp(result, 'return', {}) + + + def tearDown(self): + self.vm.shutdown() + for i in self.IMAGES + [ quorum_repair_img ]: + # Do a try/except because the test may have deleted some images + try: + os.remove(i) + except OSError: + pass + + def test_complete(self): + if not self.has_quorum(): + return + + self.assert_no_active_block_jobs() + + result = self.vm.qmp('drive-mirror', device='quorum0', sync='full', + node_name="repair0", + replaces="img1", + target=quorum_repair_img, format=iotests.imgfmt) + self.assert_qmp(result, 'return', {}) + + self.complete_and_wait(drive="quorum0") + result = self.vm.qmp('query-named-block-nodes') + self.assert_qmp(result, 'return[0]/file', quorum_repair_img) + # TODO: a better test requiring some QEMU infrastructure will be added + # to check that this file is really driven by quorum + self.vm.shutdown() + self.assertTrue(iotests.compare_images(quorum_img2, quorum_repair_img), + 'target image does not match source after mirroring') + + def test_cancel(self): + if not self.has_quorum(): + return + + self.assert_no_active_block_jobs() + + result = self.vm.qmp('drive-mirror', device='quorum0', sync='full', + node_name="repair0", + replaces="img1", + target=quorum_repair_img, format=iotests.imgfmt) + self.assert_qmp(result, 'return', {}) + + self.cancel_and_wait(drive="quorum0", force=True) + # here we check that the last registered quorum file has not been + # swapped out and unref + result = self.vm.qmp('query-named-block-nodes') + self.assert_qmp(result, 'return[0]/file', quorum_img3) + self.vm.shutdown() + + def test_cancel_after_ready(self): + if not self.has_quorum(): + return + + self.assert_no_active_block_jobs() + + result = self.vm.qmp('drive-mirror', device='quorum0', sync='full', + node_name="repair0", + replaces="img1", + target=quorum_repair_img, format=iotests.imgfmt) + self.assert_qmp(result, 'return', {}) + + self.wait_ready_and_cancel(drive="quorum0") + result = self.vm.qmp('query-named-block-nodes') + # here we check that the last registered quorum file has not been + # swapped out and unref + self.assert_qmp(result, 'return[0]/file', quorum_img3) + self.vm.shutdown() + self.assertTrue(iotests.compare_images(quorum_img2, quorum_repair_img), + 'target image does not match source after mirroring') + + def test_pause(self): + if not self.has_quorum(): + return + + self.assert_no_active_block_jobs() + + result = self.vm.qmp('drive-mirror', device='quorum0', sync='full', + node_name="repair0", + replaces="img1", + target=quorum_repair_img, format=iotests.imgfmt) + self.assert_qmp(result, 'return', {}) + + result = self.vm.qmp('block-job-pause', device='quorum0') + self.assert_qmp(result, 'return', {}) + + time.sleep(1) + result = self.vm.qmp('query-block-jobs') + offset = self.dictpath(result, 'return[0]/offset') + + time.sleep(1) + result = self.vm.qmp('query-block-jobs') + self.assert_qmp(result, 'return[0]/offset', offset) + + result = self.vm.qmp('block-job-resume', device='quorum0') + self.assert_qmp(result, 'return', {}) + + self.complete_and_wait(drive="quorum0") + self.vm.shutdown() + self.assertTrue(iotests.compare_images(quorum_img2, quorum_repair_img), + 'target image does not match source after mirroring') + + def test_medium_not_found(self): + if not self.has_quorum(): + return + + result = self.vm.qmp('drive-mirror', device='ide1-cd0', sync='full', + node_name='repair0', + replaces='img1', + target=quorum_repair_img, format=iotests.imgfmt) + self.assert_qmp(result, 'error/class', 'GenericError') + + def test_image_not_found(self): + if not self.has_quorum(): + return + + result = self.vm.qmp('drive-mirror', device='quorum0', sync='full', + node_name='repair0', + replaces='img1', + mode='existing', + target=quorum_repair_img, format=iotests.imgfmt) + self.assert_qmp(result, 'error/class', 'GenericError') + + def test_device_not_found(self): + if not self.has_quorum(): + return + + result = self.vm.qmp('drive-mirror', device='nonexistent', sync='full', + node_name='repair0', + replaces='img1', + target=quorum_repair_img, format=iotests.imgfmt) + self.assert_qmp(result, 'error/class', 'DeviceNotFound') + + def test_wrong_sync_mode(self): + if not self.has_quorum(): + return + + result = self.vm.qmp('drive-mirror', device='quorum0', + node_name='repair0', + replaces='img1', + target=quorum_repair_img, format=iotests.imgfmt) + self.assert_qmp(result, 'error/class', 'GenericError') + + def test_no_node_name(self): + if not self.has_quorum(): + return + + result = self.vm.qmp('drive-mirror', device='quorum0', sync='full', + replaces='img1', + target=quorum_repair_img, format=iotests.imgfmt) + self.assert_qmp(result, 'error/class', 'GenericError') + + def test_unexistant_replaces(self): + if not self.has_quorum(): + return + + result = self.vm.qmp('drive-mirror', device='quorum0', sync='full', + node_name='repair0', + replaces='img77', + target=quorum_repair_img, format=iotests.imgfmt) + self.assert_qmp(result, 'error/class', 'GenericError') + + def test_after_a_quorum_snapshot(self): + if not self.has_quorum(): + return + + result = self.vm.qmp('blockdev-snapshot-sync', node_name='img1', + snapshot_file=quorum_snapshot_file, + snapshot_node_name="snap1"); + + result = self.vm.qmp('drive-mirror', device='quorum0', sync='full', + node_name='repair0', + replaces="img1", + target=quorum_repair_img, format=iotests.imgfmt) + self.assert_qmp(result, 'error/class', 'GenericError') + + result = self.vm.qmp('drive-mirror', device='quorum0', sync='full', + node_name='repair0', + replaces="snap1", + target=quorum_repair_img, format=iotests.imgfmt) + self.assert_qmp(result, 'return', {}) + + self.complete_and_wait(drive="quorum0") + result = self.vm.qmp('query-named-block-nodes') + self.assert_qmp(result, 'return[0]/file', quorum_repair_img) + # TODO: a better test requiring some QEMU infrastructure will be added + # to check that this file is really driven by quorum + self.vm.shutdown() + if __name__ == '__main__': iotests.main(supported_fmts=['qcow2', 'qed']) diff --git a/tests/qemu-iotests/041.out b/tests/qemu-iotests/041.out index 6d9bee1a4..24093bc63 100644 --- a/tests/qemu-iotests/041.out +++ b/tests/qemu-iotests/041.out @@ -1,5 +1,5 @@ -........................... +...................................................... ---------------------------------------------------------------------- -Ran 27 tests +Ran 54 tests OK diff --git a/tests/qemu-iotests/049.out b/tests/qemu-iotests/049.out index ceb23289f..71ca44d76 100644 --- a/tests/qemu-iotests/049.out +++ b/tests/qemu-iotests/049.out @@ -120,7 +120,7 @@ qemu-img: kilobytes, megabytes, gigabytes, terabytes, petabytes and exabytes. qemu-img create -f qcow2 -o size=foobar TEST_DIR/t.qcow2 qemu-img: Parameter 'size' expects a size -qemu-img: TEST_DIR/t.qcow2: Invalid options for file format 'qcow2'. +qemu-img: TEST_DIR/t.qcow2: Invalid options for file format 'qcow2' == Check correct interpretation of suffixes for cluster size == diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051 index 073dc7a2d..a41334e02 100755 --- a/tests/qemu-iotests/051 +++ b/tests/qemu-iotests/051 @@ -92,6 +92,7 @@ echo run_qemu -drive file="$TEST_IMG",format=foo run_qemu -drive file="$TEST_IMG",driver=foo +run_qemu -drive file="$TEST_IMG",driver=raw,format=qcow2 echo echo === Overriding backing file === @@ -99,6 +100,11 @@ echo echo "info block" | run_qemu -drive file="$TEST_IMG",driver=qcow2,backing.file.filename="$TEST_IMG.orig" -nodefaults +# Drivers that don't support backing files +run_qemu -drive file="$TEST_IMG",driver=raw,backing.file.filename="$TEST_IMG.orig" +run_qemu -drive file="$TEST_IMG",file.backing.driver=file,file.backing.filename="$TEST_IMG.orig" +run_qemu -drive file="$TEST_IMG",file.backing.driver=qcow2,file.backing.file.filename="$TEST_IMG.orig" + echo echo === Enable and disable lazy refcounting on the command line, plus some invalid values === echo @@ -233,6 +239,10 @@ echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file="$TEST_IMG", $QEMU_IO -c "read -P 0x22 0 4k" "$TEST_IMG" | _filter_qemu_io +echo -e 'qemu-io ide0-hd0 "write -P 0x33 0 4k"\ncommit ide0-hd0' | run_qemu -drive file="$TEST_IMG",snapshot=on | _filter_qemu_io + +$QEMU_IO -c "read -P 0x33 0 4k" "$TEST_IMG" | _filter_qemu_io + # success, all done echo "*** done" rm -f $seq.full diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out index 01b038447..d7b0f503a 100644 --- a/tests/qemu-iotests/051.out +++ b/tests/qemu-iotests/051.out @@ -38,7 +38,10 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=foo QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=foo: 'foo' invalid format Testing: -drive file=TEST_DIR/t.qcow2,driver=foo -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=foo: could not open disk image TEST_DIR/t.qcow2: Invalid driver: 'foo' +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=foo: could not open disk image TEST_DIR/t.qcow2: Unknown driver 'foo' + +Testing: -drive file=TEST_DIR/t.qcow2,driver=raw,format=qcow2 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=raw,format=qcow2: could not open disk image TEST_DIR/t.qcow2: Driver specified twice === Overriding backing file === @@ -50,6 +53,15 @@ ide0-hd0: TEST_DIR/t.qcow2 (qcow2) Backing file: TEST_DIR/t.qcow2.orig (chain depth: 1) (qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K +Testing: -drive file=TEST_DIR/t.qcow2,driver=raw,backing.file.filename=TEST_DIR/t.qcow2.orig +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=raw,backing.file.filename=TEST_DIR/t.qcow2.orig: could not open disk image TEST_DIR/t.qcow2: Driver doesn't support backing files + +Testing: -drive file=TEST_DIR/t.qcow2,file.backing.driver=file,file.backing.filename=TEST_DIR/t.qcow2.orig +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.backing.driver=file,file.backing.filename=TEST_DIR/t.qcow2.orig: could not open disk image TEST_DIR/t.qcow2: Driver doesn't support backing files + +Testing: -drive file=TEST_DIR/t.qcow2,file.backing.driver=qcow2,file.backing.file.filename=TEST_DIR/t.qcow2.orig +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.backing.driver=qcow2,file.backing.file.filename=TEST_DIR/t.qcow2.orig: could not open disk image TEST_DIR/t.qcow2: Driver doesn't support backing files + === Enable and disable lazy refcounting on the command line, plus some invalid values === @@ -358,4 +370,14 @@ wrote 4096/4096 bytes at offset 0 read 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io i[K[D[D[D[D[D[D[D[D[Dqemu-io id[K[D[D[D[D[D[D[D[D[D[Dqemu-io ide[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-h[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x3[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x33[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x33 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x33 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x33 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x33 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x33 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x33 0 4k"[K +wrote 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +(qemu) c[K[Dco[K[D[Dcom[K[D[D[Dcomm[K[D[D[D[Dcommi[K[D[D[D[D[Dcommit[K[D[D[D[D[D[Dcommit [K[D[D[D[D[D[D[Dcommit i[K[D[D[D[D[D[D[D[Dcommit id[K[D[D[D[D[D[D[D[D[Dcommit ide[K[D[D[D[D[D[D[D[D[D[Dcommit ide0[K[D[D[D[D[D[D[D[D[D[D[Dcommit ide0-[K[D[D[D[D[D[D[D[D[D[D[D[Dcommit ide0-h[K[D[D[D[D[D[D[D[D[D[D[D[D[Dcommit ide0-hd[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dcommit ide0-hd0[K +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +read 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) *** done diff --git a/tests/qemu-iotests/054 b/tests/qemu-iotests/054 index c8b7082b4..bd94153d6 100755 --- a/tests/qemu-iotests/054 +++ b/tests/qemu-iotests/054 @@ -49,7 +49,7 @@ _make_test_img $((1024*1024))T echo echo "creating too large image (1 EB) using qcow2.py" _make_test_img 4G -./qcow2.py "$TEST_IMG" set-header size $((1024 ** 6)) +$PYTHON qcow2.py "$TEST_IMG" set-header size $((1024 ** 6)) _check_test_img # success, all done diff --git a/tests/qemu-iotests/056 b/tests/qemu-iotests/056 index 63893423c..54e4bd069 100755 --- a/tests/qemu-iotests/056 +++ b/tests/qemu-iotests/056 @@ -57,14 +57,7 @@ class TestSyncModesNoneAndTop(iotests.QMPTestCase): format=iotests.imgfmt, target=target_img) self.assert_qmp(result, 'return', {}) - # Custom completed check as we are not copying all data. - completed = False - while not completed: - for event in self.vm.get_qmp_events(wait=True): - if event['event'] == 'BLOCK_JOB_COMPLETED': - self.assert_qmp(event, 'data/device', 'drive0') - self.assert_qmp_absent(event, 'data/error') - completed = True + self.wait_until_completed(check_offset=False) self.assert_no_active_block_jobs() self.vm.shutdown() diff --git a/tests/qemu-iotests/059 b/tests/qemu-iotests/059 index ca5aa16ff..26a2fd3e0 100755 --- a/tests/qemu-iotests/059 +++ b/tests/qemu-iotests/059 @@ -104,6 +104,13 @@ truncate -s 10M $TEST_IMG _img_info echo +echo "=== Converting to streamOptimized from image with small cluster size===" +TEST_IMG="$TEST_IMG.qcow2" IMGFMT=qcow2 IMGOPTS="cluster_size=4096" _make_test_img 1G +$QEMU_IO -c "write -P 0xa 0 512" "$TEST_IMG.qcow2" | _filter_qemu_io +$QEMU_IO -c "write -P 0xb 10240 512" "$TEST_IMG.qcow2" | _filter_qemu_io +$QEMU_IMG convert -f qcow2 -O vmdk -o subformat=streamOptimized "$TEST_IMG.qcow2" "$TEST_IMG" 2>&1 + +echo echo "=== Testing version 3 ===" _use_sample_img iotest-version3.vmdk.bz2 _img_info diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out index 3371c867b..eba0dedda 100644 --- a/tests/qemu-iotests/059.out +++ b/tests/qemu-iotests/059.out @@ -2046,10 +2046,18 @@ RW 12582912 VMFS "dummy.IMGFMT" 1 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=107374182400 qemu-img: Could not open 'TEST_DIR/t.IMGFMT': File truncated, expecting at least 13172736 bytes +=== Converting to streamOptimized from image with small cluster size=== +Formatting 'TEST_DIR/t.vmdk.IMGFMT', fmt=IMGFMT size=1073741824 +wrote 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 512/512 bytes at offset 10240 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + === Testing version 3 === image: TEST_DIR/iotest-version3.IMGFMT file format: IMGFMT virtual size: 1.0G (1073741824 bytes) +cluster_size: 65536 === Testing 4TB monolithicFlat creation and IO === Formatting 'TEST_DIR/iotest-version3.IMGFMT', fmt=IMGFMT size=4398046511104 diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060 index f0116aab1..3cffc12fe 100755 --- a/tests/qemu-iotests/060 +++ b/tests/qemu-iotests/060 @@ -68,13 +68,13 @@ poke_file "$TEST_IMG" "$l1_offset" "\x80\x00\x00\x00\x00\x03\x00\x00" _check_test_img # The corrupt bit should not be set anyway -./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features # Try to write something, thereby forcing the corrupt bit to be set $QEMU_IO -c "$OPEN_RW" -c "write -P 0x2a 0 512" | _filter_qemu_io # The corrupt bit must now be set -./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features # Try to open the image R/W (which should fail) $QEMU_IO -c "$OPEN_RW" -c "read 0 512" 2>&1 | _filter_qemu_io \ @@ -99,19 +99,19 @@ poke_file "$TEST_IMG" "$(($rb_offset+8))" "\x00\x01" # Redirect new data cluster onto refcount block poke_file "$TEST_IMG" "$l2_offset" "\x80\x00\x00\x00\x00\x02\x00\x00" _check_test_img -./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features $QEMU_IO -c "$OPEN_RW" -c "write -P 0x2a 0 512" | _filter_qemu_io -./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features # Try to fix it _check_test_img -r all # The corrupt bit should be cleared -./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features # Look if it's really really fixed $QEMU_IO -c "$OPEN_RW" -c "write -P 0x2a 0 512" | _filter_qemu_io -./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features echo echo "=== Testing cluster data reference into inactive L2 table ===" @@ -124,13 +124,13 @@ $QEMU_IO -c "$OPEN_RW" -c "write -P 2 0 512" | _filter_qemu_io poke_file "$TEST_IMG" "$l2_offset_after_snapshot" \ "\x80\x00\x00\x00\x00\x04\x00\x00" _check_test_img -./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features $QEMU_IO -c "$OPEN_RW" -c "write -P 3 0 512" | _filter_qemu_io -./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features _check_test_img -r all -./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features $QEMU_IO -c "$OPEN_RW" -c "write -P 4 0 512" | _filter_qemu_io -./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features +$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features # Check data $QEMU_IO -c "$OPEN_RO" -c "read -P 4 0 512" | _filter_qemu_io diff --git a/tests/qemu-iotests/061 b/tests/qemu-iotests/061 index d3a6b388b..ab98def6d 100755 --- a/tests/qemu-iotests/061 +++ b/tests/qemu-iotests/061 @@ -48,9 +48,9 @@ echo "=== Testing version downgrade with zero expansion ===" echo IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img 64M $QEMU_IO -c "write -z 0 128k" "$TEST_IMG" | _filter_qemu_io -./qcow2.py "$TEST_IMG" dump-header +$PYTHON qcow2.py "$TEST_IMG" dump-header $QEMU_IMG amend -o "compat=0.10" "$TEST_IMG" -./qcow2.py "$TEST_IMG" dump-header +$PYTHON qcow2.py "$TEST_IMG" dump-header $QEMU_IO -c "read -P 0 0 128k" "$TEST_IMG" | _filter_qemu_io _check_test_img @@ -59,9 +59,9 @@ echo "=== Testing dirty version downgrade ===" echo IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img 64M $QEMU_IO -c "write -P 0x2a 0 128k" -c flush -c abort "$TEST_IMG" | _filter_qemu_io -./qcow2.py "$TEST_IMG" dump-header +$PYTHON qcow2.py "$TEST_IMG" dump-header $QEMU_IMG amend -o "compat=0.10" "$TEST_IMG" -./qcow2.py "$TEST_IMG" dump-header +$PYTHON qcow2.py "$TEST_IMG" dump-header $QEMU_IO -c "read -P 0x2a 0 128k" "$TEST_IMG" | _filter_qemu_io _check_test_img @@ -69,11 +69,11 @@ echo echo "=== Testing version downgrade with unknown compat/autoclear flags ===" echo IMGOPTS="compat=1.1" _make_test_img 64M -./qcow2.py "$TEST_IMG" set-feature-bit compatible 42 -./qcow2.py "$TEST_IMG" set-feature-bit autoclear 42 -./qcow2.py "$TEST_IMG" dump-header +$PYTHON qcow2.py "$TEST_IMG" set-feature-bit compatible 42 +$PYTHON qcow2.py "$TEST_IMG" set-feature-bit autoclear 42 +$PYTHON qcow2.py "$TEST_IMG" dump-header $QEMU_IMG amend -o "compat=0.10" "$TEST_IMG" -./qcow2.py "$TEST_IMG" dump-header +$PYTHON qcow2.py "$TEST_IMG" dump-header _check_test_img echo @@ -81,9 +81,9 @@ echo "=== Testing version upgrade and resize ===" echo IMGOPTS="compat=0.10" _make_test_img 64M $QEMU_IO -c "write -P 0x2a 42M 64k" "$TEST_IMG" | _filter_qemu_io -./qcow2.py "$TEST_IMG" dump-header +$PYTHON qcow2.py "$TEST_IMG" dump-header $QEMU_IMG amend -o "compat=1.1,lazy_refcounts=on,size=128M" "$TEST_IMG" -./qcow2.py "$TEST_IMG" dump-header +$PYTHON qcow2.py "$TEST_IMG" dump-header $QEMU_IO -c "read -P 0x2a 42M 64k" "$TEST_IMG" | _filter_qemu_io _check_test_img @@ -92,9 +92,9 @@ echo "=== Testing dirty lazy_refcounts=off ===" echo IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img 64M $QEMU_IO -c "write -P 0x2a 0 128k" -c flush -c abort "$TEST_IMG" | _filter_qemu_io -./qcow2.py "$TEST_IMG" dump-header +$PYTHON qcow2.py "$TEST_IMG" dump-header $QEMU_IMG amend -o "lazy_refcounts=off" "$TEST_IMG" -./qcow2.py "$TEST_IMG" dump-header +$PYTHON qcow2.py "$TEST_IMG" dump-header $QEMU_IO -c "read -P 0x2a 0 128k" "$TEST_IMG" | _filter_qemu_io _check_test_img diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out index 4027e0077..e3724700b 100644 --- a/tests/qemu-iotests/061.out +++ b/tests/qemu-iotests/061.out @@ -281,7 +281,7 @@ Lazy refcounts only supported with compatibility level 1.1 and above (use compat qemu-img: Error while amending options: Invalid argument Unknown compatibility level 0.42. qemu-img: Error while amending options: Invalid argument -Unknown option 'foo' +qemu-img: Invalid parameter 'foo' qemu-img: Invalid options for file format 'qcow2' Changing the cluster size is not supported. qemu-img: Error while amending options: Operation not supported diff --git a/tests/qemu-iotests/065 b/tests/qemu-iotests/065 index ab5445f62..e89b61d70 100755 --- a/tests/qemu-iotests/065 +++ b/tests/qemu-iotests/065 @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python # # Test for additional information emitted by qemu-img info on qcow2 # images diff --git a/tests/qemu-iotests/067.out b/tests/qemu-iotests/067.out index 8d271cc41..7e090b95a 100644 --- a/tests/qemu-iotests/067.out +++ b/tests/qemu-iotests/067.out @@ -6,7 +6,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk -device virtio-blk-pci,drive=disk,id=virtio0 QMP_VERSION {"return": {}} -{"return": [{"io-status": "ok", "device": "disk", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "type": "unknown"}, {"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]} +{"return": [{"io-status": "ok", "device": "disk", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "type": "unknown"}, {"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]} {"return": {}} {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"path": "/machine/peripheral/virtio0/virtio-backend"}} @@ -24,7 +24,7 @@ QMP_VERSION Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk QMP_VERSION {"return": {}} -{"return": [{"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}, {"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]} +{"return": [{"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}, {"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]} {"return": {}} {"return": {}} {"return": {}} @@ -44,7 +44,7 @@ Testing: QMP_VERSION {"return": {}} {"return": "OK\r\n"} -{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]} +{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]} {"return": {}} {"return": {}} {"return": {}} @@ -64,14 +64,14 @@ Testing: QMP_VERSION {"return": {}} {"return": {}} -{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]} +{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]} {"return": {}} {"return": {}} {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"path": "/machine/peripheral/virtio0/virtio-backend"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"device": "virtio0", "path": "/machine/peripheral/virtio0"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "RESET"} -{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"io-status": "ok", "device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]} +{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"io-status": "ok", "device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]} {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}} diff --git a/tests/qemu-iotests/070 b/tests/qemu-iotests/070 index ce71fa4a2..ea0dae7e9 100755 --- a/tests/qemu-iotests/070 +++ b/tests/qemu-iotests/070 @@ -72,6 +72,13 @@ echo "=== Verify open image read-only succeeds after log replay ===" $QEMU_IO -r -c "read -pP 0xa5 0 18M" "$TEST_IMG" 2>&1 | _filter_testdir \ | _filter_qemu_io +_cleanup_test_img +_use_sample_img test-disk2vhd.vhdx.bz2 + +echo +echo "=== Verify image created by Disk2VHD can be opened ===" +$QEMU_IMG info "$TEST_IMG" 2>&1 | _filter_testdir | _filter_qemu + # success, all done echo "*** done" rm -f $seq.full diff --git a/tests/qemu-iotests/070.out b/tests/qemu-iotests/070.out index 922d62cb5..15f1fc147 100644 --- a/tests/qemu-iotests/070.out +++ b/tests/qemu-iotests/070.out @@ -18,4 +18,11 @@ No errors were found on the image. === Verify open image read-only succeeds after log replay === read 18874368/18874368 bytes at offset 0 18 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +=== Verify image created by Disk2VHD can be opened === +image: TEST_DIR/test-disk2vhd.vhdx +file format: vhdx +virtual size: 256M (268435456 bytes) +disk size: 260M +cluster_size: 2097152 *** done diff --git a/tests/qemu-iotests/081 b/tests/qemu-iotests/081 index b512d00cc..7ae4be205 100755 --- a/tests/qemu-iotests/081 +++ b/tests/qemu-iotests/081 @@ -134,15 +134,28 @@ run_qemu -drive "file=$TEST_DIR/2.raw,format=$IMGFMT,if=none,id=drive2" <<EOF EOF echo +echo "== using quorum rewrite corrupted mode ==" + +quorum="$quorum,file.rewrite-corrupted=on" + +$QEMU_IO -c "open -o $quorum" -c "read -P 0x32 0 $size" | _filter_qemu_io + +echo +echo "== checking that quorum has corrected the corrupted file ==" + +$QEMU_IO -c "read -P 0x32 0 $size" "$TEST_DIR/2.raw" | _filter_qemu_io + +echo echo "== breaking quorum ==" $QEMU_IO -c "write -P 0x41 0 $size" "$TEST_DIR/1.raw" | _filter_qemu_io +$QEMU_IO -c "write -P 0x42 0 $size" "$TEST_DIR/2.raw" | _filter_qemu_io + echo echo "== checking that quorum is broken ==" $QEMU_IO -c "open -o $quorum" -c "read -P 0x32 0 $size" | _filter_qemu_io - # success, all done echo "*** done" rm -f $seq.full diff --git a/tests/qemu-iotests/081.out b/tests/qemu-iotests/081.out index 84aeb0c73..073515ea5 100644 --- a/tests/qemu-iotests/081.out +++ b/tests/qemu-iotests/081.out @@ -40,10 +40,20 @@ read 10485760/10485760 bytes at offset 0 {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}} +== using quorum rewrite corrupted mode == +read 10485760/10485760 bytes at offset 0 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== checking that quorum has corrected the corrupted file == +read 10485760/10485760 bytes at offset 0 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + == breaking quorum == wrote 10485760/10485760 bytes at offset 0 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 10485760/10485760 bytes at offset 0 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) == checking that quorum is broken == -qemu-io: can't open device (null): Could not read image for determining its format: Input/output error +qemu-io: can't open: Could not read image for determining its format: Input/output error *** done diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out index 28309a032..413e7ef39 100644 --- a/tests/qemu-iotests/082.out +++ b/tests/qemu-iotests/082.out @@ -66,6 +66,7 @@ encryption Encrypt the image cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata) lazy_refcounts Postpone refcount updates +nocow Turn off copy-on-write (valid only on btrfs) Testing: create -f qcow2 -o ? TEST_DIR/t.qcow2 128M Supported options: @@ -77,6 +78,7 @@ encryption Encrypt the image cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata) lazy_refcounts Postpone refcount updates +nocow Turn off copy-on-write (valid only on btrfs) Testing: create -f qcow2 -o cluster_size=4k,help TEST_DIR/t.qcow2 128M Supported options: @@ -88,6 +90,7 @@ encryption Encrypt the image cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata) lazy_refcounts Postpone refcount updates +nocow Turn off copy-on-write (valid only on btrfs) Testing: create -f qcow2 -o cluster_size=4k,? TEST_DIR/t.qcow2 128M Supported options: @@ -99,6 +102,7 @@ encryption Encrypt the image cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata) lazy_refcounts Postpone refcount updates +nocow Turn off copy-on-write (valid only on btrfs) Testing: create -f qcow2 -o help,cluster_size=4k TEST_DIR/t.qcow2 128M Supported options: @@ -110,6 +114,7 @@ encryption Encrypt the image cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata) lazy_refcounts Postpone refcount updates +nocow Turn off copy-on-write (valid only on btrfs) Testing: create -f qcow2 -o ?,cluster_size=4k TEST_DIR/t.qcow2 128M Supported options: @@ -121,6 +126,7 @@ encryption Encrypt the image cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata) lazy_refcounts Postpone refcount updates +nocow Turn off copy-on-write (valid only on btrfs) Testing: create -f qcow2 -o cluster_size=4k -o help TEST_DIR/t.qcow2 128M Supported options: @@ -132,6 +138,7 @@ encryption Encrypt the image cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata) lazy_refcounts Postpone refcount updates +nocow Turn off copy-on-write (valid only on btrfs) Testing: create -f qcow2 -o cluster_size=4k -o ? TEST_DIR/t.qcow2 128M Supported options: @@ -143,6 +150,7 @@ encryption Encrypt the image cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata) lazy_refcounts Postpone refcount updates +nocow Turn off copy-on-write (valid only on btrfs) Testing: create -f qcow2 -o backing_file=TEST_DIR/t.qcow2,,help TEST_DIR/t.qcow2 128M Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/t.qcow2,help' encryption=off cluster_size=65536 lazy_refcounts=off @@ -247,6 +255,7 @@ encryption Encrypt the image cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata) lazy_refcounts Postpone refcount updates +nocow Turn off copy-on-write (valid only on btrfs) Testing: convert -O qcow2 -o ? TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base Supported options: @@ -258,6 +267,7 @@ encryption Encrypt the image cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata) lazy_refcounts Postpone refcount updates +nocow Turn off copy-on-write (valid only on btrfs) Testing: convert -O qcow2 -o cluster_size=4k,help TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base Supported options: @@ -269,6 +279,7 @@ encryption Encrypt the image cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata) lazy_refcounts Postpone refcount updates +nocow Turn off copy-on-write (valid only on btrfs) Testing: convert -O qcow2 -o cluster_size=4k,? TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base Supported options: @@ -280,6 +291,7 @@ encryption Encrypt the image cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata) lazy_refcounts Postpone refcount updates +nocow Turn off copy-on-write (valid only on btrfs) Testing: convert -O qcow2 -o help,cluster_size=4k TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base Supported options: @@ -291,6 +303,7 @@ encryption Encrypt the image cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata) lazy_refcounts Postpone refcount updates +nocow Turn off copy-on-write (valid only on btrfs) Testing: convert -O qcow2 -o ?,cluster_size=4k TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base Supported options: @@ -302,6 +315,7 @@ encryption Encrypt the image cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata) lazy_refcounts Postpone refcount updates +nocow Turn off copy-on-write (valid only on btrfs) Testing: convert -O qcow2 -o cluster_size=4k -o help TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base Supported options: @@ -313,6 +327,7 @@ encryption Encrypt the image cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata) lazy_refcounts Postpone refcount updates +nocow Turn off copy-on-write (valid only on btrfs) Testing: convert -O qcow2 -o cluster_size=4k -o ? TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base Supported options: @@ -324,6 +339,7 @@ encryption Encrypt the image cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata) lazy_refcounts Postpone refcount updates +nocow Turn off copy-on-write (valid only on btrfs) Testing: convert -O qcow2 -o backing_file=TEST_DIR/t.qcow2,,help TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base qemu-img: Could not open 'TEST_DIR/t.qcow2.base': Could not open backing file: Could not open 'TEST_DIR/t.qcow2,help': No such file or directory @@ -417,6 +433,7 @@ encryption Encrypt the image cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata) lazy_refcounts Postpone refcount updates +nocow Turn off copy-on-write (valid only on btrfs) Testing: amend -f qcow2 -o ? TEST_DIR/t.qcow2 Supported options: @@ -428,6 +445,7 @@ encryption Encrypt the image cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata) lazy_refcounts Postpone refcount updates +nocow Turn off copy-on-write (valid only on btrfs) Testing: amend -f qcow2 -o cluster_size=4k,help TEST_DIR/t.qcow2 Supported options: @@ -439,6 +457,7 @@ encryption Encrypt the image cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata) lazy_refcounts Postpone refcount updates +nocow Turn off copy-on-write (valid only on btrfs) Testing: amend -f qcow2 -o cluster_size=4k,? TEST_DIR/t.qcow2 Supported options: @@ -450,6 +469,7 @@ encryption Encrypt the image cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata) lazy_refcounts Postpone refcount updates +nocow Turn off copy-on-write (valid only on btrfs) Testing: amend -f qcow2 -o help,cluster_size=4k TEST_DIR/t.qcow2 Supported options: @@ -461,6 +481,7 @@ encryption Encrypt the image cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata) lazy_refcounts Postpone refcount updates +nocow Turn off copy-on-write (valid only on btrfs) Testing: amend -f qcow2 -o ?,cluster_size=4k TEST_DIR/t.qcow2 Supported options: @@ -472,6 +493,7 @@ encryption Encrypt the image cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata) lazy_refcounts Postpone refcount updates +nocow Turn off copy-on-write (valid only on btrfs) Testing: amend -f qcow2 -o cluster_size=4k -o help TEST_DIR/t.qcow2 Supported options: @@ -483,6 +505,7 @@ encryption Encrypt the image cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata) lazy_refcounts Postpone refcount updates +nocow Turn off copy-on-write (valid only on btrfs) Testing: amend -f qcow2 -o cluster_size=4k -o ? TEST_DIR/t.qcow2 Supported options: @@ -494,6 +517,7 @@ encryption Encrypt the image cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata) lazy_refcounts Postpone refcount updates +nocow Turn off copy-on-write (valid only on btrfs) Testing: amend -f qcow2 -o backing_file=TEST_DIR/t.qcow2,,help TEST_DIR/t.qcow2 diff --git a/tests/qemu-iotests/083 b/tests/qemu-iotests/083 index f76453478..991a9d91d 100755 --- a/tests/qemu-iotests/083 +++ b/tests/qemu-iotests/083 @@ -44,7 +44,7 @@ choose_tcp_port() { wait_for_tcp_port() { while ! (netstat --tcp --listening --numeric | \ - grep "$1.*0.0.0.0:\*.*LISTEN") 2>&1 >/dev/null; do + grep "$1.*0\\.0\\.0\\.0:\\*.*LISTEN") 2>&1 >/dev/null; do sleep 0.1 done } @@ -55,8 +55,8 @@ filter_nbd() { # callbacks sometimes, making them unreliable. # # Filter out the TCP port number since this changes between runs. - sed -e 's#^nbd.c:.*##g' \ - -e 's#nbd:127.0.0.1:[^:]*:#nbd:127.0.0.1:PORT:#g' + sed -e 's#^.*nbd\.c:.*##g' \ + -e 's#nbd:127\.0\.0\.1:[^:]*:#nbd:127\.0\.0\.1:PORT:#g' } check_disconnect() { @@ -81,8 +81,8 @@ EOF nbd_url="nbd:127.0.0.1:$port:exportname=foo" fi - ./nbd-fault-injector.py $extra_args "127.0.0.1:$port" "$TEST_DIR/nbd-fault-injector.conf" 2>&1 >/dev/null & - wait_for_tcp_port "127.0.0.1:$port" + $PYTHON nbd-fault-injector.py $extra_args "127.0.0.1:$port" "$TEST_DIR/nbd-fault-injector.conf" 2>&1 >/dev/null & + wait_for_tcp_port "127\\.0\\.0\\.1:$port" $QEMU_IO -c "read 0 512" "$nbd_url" 2>&1 | _filter_qemu_io | filter_nbd echo diff --git a/tests/qemu-iotests/084.out b/tests/qemu-iotests/084.out index e681924b8..c7120d9b0 100644 --- a/tests/qemu-iotests/084.out +++ b/tests/qemu-iotests/084.out @@ -4,10 +4,7 @@ QA output created by 084 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 Test 1: Maximum size (1024 TB): -image: TEST_DIR/t.IMGFMT -file format: IMGFMT -virtual size: 1024T (1125899905794048 bytes) -cluster_size: 1048576 +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Could not open 'TEST_DIR/t.IMGFMT': Invalid argument Test 2: Size too large (1024TB + 1) qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Unsupported VDI image size (size is 0x3fffffff10000, max supported is 0x3fffffff00000) diff --git a/tests/qemu-iotests/085 b/tests/qemu-iotests/085 index 33c8dc410..56cd6f89b 100755 --- a/tests/qemu-iotests/085 +++ b/tests/qemu-iotests/085 @@ -30,10 +30,6 @@ echo "QA output created by $seq" here=`pwd` status=1 # failure is the default! -qemu_pid= - -QMP_IN="${TEST_DIR}/qmp-in-$$" -QMP_OUT="${TEST_DIR}/qmp-out-$$" snapshot_virt0="snapshot-v0.qcow2" snapshot_virt1="snapshot-v1.qcow2" @@ -42,10 +38,7 @@ MAX_SNAPSHOTS=10 _cleanup() { - kill -KILL ${qemu_pid} - wait ${qemu_pid} 2>/dev/null # silent kill - - rm -f "${QMP_IN}" "${QMP_OUT}" + _cleanup_qemu for i in $(seq 1 ${MAX_SNAPSHOTS}) do rm -f "${TEST_DIR}/${i}-${snapshot_virt0}" @@ -59,43 +52,12 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 # get standard environment, filters and checks . ./common.rc . ./common.filter +. ./common.qemu _supported_fmt qcow2 _supported_proto file _supported_os Linux -# Wait for expected QMP response from QEMU. Will time out -# after 10 seconds, which counts as failure. -# -# $1 is the string to expect -# -# If $silent is set to anything but an empty string, then -# response is not echoed out. -function timed_wait_for() -{ - while read -t 10 resp <&5 - do - if [ "${silent}" == "" ]; then - echo "${resp}" | _filter_testdir | _filter_qemu - fi - grep -q "${1}" < <(echo ${resp}) - if [ $? -eq 0 ]; then - return - fi - done - echo "Timeout waiting for ${1}" - exit 1 # Timeout means the test failed -} - -# Sends QMP command to QEMU, and waits for the expected response -# -# ${1}: String of the QMP command to send -# ${2}: String that the QEMU response should contain -function send_qmp_cmd() -{ - echo "${1}" >&6 - timed_wait_for "${2}" -} # ${1}: unique identifier for the snapshot filename function create_single_snapshot() @@ -104,7 +66,7 @@ function create_single_snapshot() 'arguments': { 'device': 'virtio0', 'snapshot-file':'"${TEST_DIR}/${1}-${snapshot_virt0}"', 'format': 'qcow2' } }" - send_qmp_cmd "${cmd}" "return" + _send_qemu_cmd $h "${cmd}" "return" } # ${1}: unique identifier for the snapshot filename @@ -120,14 +82,11 @@ function create_group_snapshot() 'snapshot-file': '"${TEST_DIR}/${1}-${snapshot_virt1}"' } } ] } }" - send_qmp_cmd "${cmd}" "return" + _send_qemu_cmd $h "${cmd}" "return" } size=128M -mkfifo "${QMP_IN}" -mkfifo "${QMP_OUT}" - _make_test_img $size mv "${TEST_IMG}" "${TEST_IMG}.orig" _make_test_img $size @@ -136,23 +95,15 @@ echo echo === Running QEMU === echo -"${QEMU}" -nographic -monitor none -serial none -qmp stdio\ - -drive file="${TEST_IMG}.orig",if=virtio\ - -drive file="${TEST_IMG}",if=virtio 2>&1 >"${QMP_OUT}" <"${QMP_IN}"& -qemu_pid=$! - -# redirect fifos to file descriptors, to keep from blocking -exec 5<"${QMP_OUT}" -exec 6>"${QMP_IN}" - -# Don't print response, since it has version information in it -silent=yes timed_wait_for "capabilities" +qemu_comm_method="qmp" +_launch_qemu -drive file="${TEST_IMG}.orig",if=virtio -drive file="${TEST_IMG}",if=virtio +h=$QEMU_HANDLE echo echo === Sending capabilities === echo -send_qmp_cmd "{ 'execute': 'qmp_capabilities' }" "return" +_send_qemu_cmd $h "{ 'execute': 'qmp_capabilities' }" "return" echo echo === Create a single snapshot on virtio0 === @@ -165,16 +116,16 @@ echo echo === Invalid command - missing device and nodename === echo -send_qmp_cmd "{ 'execute': 'blockdev-snapshot-sync', - 'arguments': { 'snapshot-file':'"${TEST_DIR}"/1-${snapshot_virt0}', +_send_qemu_cmd $h "{ 'execute': 'blockdev-snapshot-sync', + 'arguments': { 'snapshot-file':'"${TEST_DIR}/1-${snapshot_virt0}"', 'format': 'qcow2' } }" "error" echo echo === Invalid command - missing snapshot-file === echo -send_qmp_cmd "{ 'execute': 'blockdev-snapshot-sync', - 'arguments': { 'device': 'virtio0', +_send_qemu_cmd $h "{ 'execute': 'blockdev-snapshot-sync', + 'arguments': { 'device': 'virtio0', 'format': 'qcow2' } }" "error" echo echo diff --git a/tests/qemu-iotests/086 b/tests/qemu-iotests/086 index 48fe85bc4..d9a80cf86 100755 --- a/tests/qemu-iotests/086 +++ b/tests/qemu-iotests/086 @@ -51,10 +51,10 @@ function run_qemu_img() size=128M _make_test_img $size -$QEMU_IO -c 'write 0 1M' $TEST_IMG | _filter_qemu_io -$QEMU_IO -c 'write 2M 1M' $TEST_IMG | _filter_qemu_io -$QEMU_IO -c 'write 4M 1M' $TEST_IMG | _filter_qemu_io -$QEMU_IO -c 'write 32M 1M' $TEST_IMG | _filter_qemu_io +$QEMU_IO -c 'write 0 1M' "$TEST_IMG" | _filter_qemu_io +$QEMU_IO -c 'write 2M 1M' "$TEST_IMG" | _filter_qemu_io +$QEMU_IO -c 'write 4M 1M' "$TEST_IMG" | _filter_qemu_io +$QEMU_IO -c 'write 32M 1M' "$TEST_IMG" | _filter_qemu_io $QEMU_IMG convert -p -O $IMGFMT -f $IMGFMT "$TEST_IMG" "$TEST_IMG".base 2>&1 |\ _filter_testdir | sed -e 's/\r/\n/g' diff --git a/tests/qemu-iotests/087 b/tests/qemu-iotests/087 index a38bb702b..82c56b139 100755 --- a/tests/qemu-iotests/087 +++ b/tests/qemu-iotests/087 @@ -73,6 +73,91 @@ run_qemu <<EOF EOF echo +echo === Duplicate ID === +echo + +run_qemu <<EOF +{ "execute": "qmp_capabilities" } +{ "execute": "blockdev-add", + "arguments": { + "options": { + "driver": "$IMGFMT", + "id": "disk", + "node-name": "test-node", + "file": { + "driver": "file", + "filename": "$TEST_IMG" + } + } + } + } +{ "execute": "blockdev-add", + "arguments": { + "options": { + "driver": "$IMGFMT", + "id": "disk", + "file": { + "driver": "file", + "filename": "$TEST_IMG" + } + } + } + } +{ "execute": "blockdev-add", + "arguments": { + "options": { + "driver": "$IMGFMT", + "id": "test-node", + "file": { + "driver": "file", + "filename": "$TEST_IMG" + } + } + } + } +{ "execute": "blockdev-add", + "arguments": { + "options": { + "driver": "$IMGFMT", + "id": "disk2", + "node-name": "disk", + "file": { + "driver": "file", + "filename": "$TEST_IMG" + } + } + } + } +{ "execute": "blockdev-add", + "arguments": { + "options": { + "driver": "$IMGFMT", + "id": "disk2", + "node-name": "test-node", + "file": { + "driver": "file", + "filename": "$TEST_IMG" + } + } + } + } +{ "execute": "blockdev-add", + "arguments": { + "options": { + "driver": "$IMGFMT", + "id": "disk3", + "node-name": "disk3", + "file": { + "driver": "file", + "filename": "$TEST_IMG" + } + } + } + } +{ "execute": "quit" } +EOF + +echo echo === aio=native without O_DIRECT === echo diff --git a/tests/qemu-iotests/087.out b/tests/qemu-iotests/087.out index e65dcdfbb..7fbee3ff5 100644 --- a/tests/qemu-iotests/087.out +++ b/tests/qemu-iotests/087.out @@ -13,6 +13,24 @@ QMP_VERSION {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}} +=== Duplicate ID === + +Testing: +QMP_VERSION +{"return": {}} +{"return": {}} +{"error": {"class": "GenericError", "desc": "Device with id 'disk' already exists"}} +{"error": {"class": "GenericError", "desc": "Device with node-name 'test-node' already exists"}} +main-loop: WARNING: I/O thread spun for 1000 iterations +{"error": {"class": "GenericError", "desc": "could not open disk image disk2: node-name=disk is conflicting with a device id"}} +{"error": {"class": "GenericError", "desc": "could not open disk image disk2: Duplicate node name"}} +{"error": {"class": "GenericError", "desc": "could not open disk image disk3: node-name=disk3 is conflicting with a device id"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}} + + === aio=native without O_DIRECT === Testing: diff --git a/tests/qemu-iotests/089 b/tests/qemu-iotests/089 new file mode 100755 index 000000000..dffc977e1 --- /dev/null +++ b/tests/qemu-iotests/089 @@ -0,0 +1,129 @@ +#!/bin/bash +# +# Test case for support of JSON filenames +# +# Copyright (C) 2014 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +# creator +owner=mreitz@redhat.com + +seq="$(basename $0)" +echo "QA output created by $seq" + +here="$PWD" +tmp=/tmp/$$ +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_supported_fmt qcow2 +_supported_proto file +_supported_os Linux + +# Using an image filename containing quotation marks will render the JSON data +# below invalid. In that case, we have little choice but simply not to run this +# test. +case $TEST_IMG in + *'"'*) + _notrun "image filename may not contain quotation marks" + ;; +esac + +IMG_SIZE=64M + +# Taken from test 072 +echo +echo "=== Testing nested image formats ===" +echo + +TEST_IMG="$TEST_IMG.base" _make_test_img $IMG_SIZE + +$QEMU_IO -c 'write -P 42 0 512' -c 'write -P 23 512 512' \ + -c 'write -P 66 1024 512' "$TEST_IMG.base" | _filter_qemu_io + +$QEMU_IMG convert -f raw -O $IMGFMT "$TEST_IMG.base" "$TEST_IMG" + +$QEMU_IO -c 'read -P 42 0 512' -c 'read -P 23 512 512' \ + -c 'read -P 66 1024 512' "json:{ + \"driver\": \"$IMGFMT\", + \"file\": { + \"driver\": \"$IMGFMT\", + \"file\": { + \"filename\": \"$TEST_IMG\" + } + } +}" | _filter_qemu_io + +# This should fail (see test 072) +$QEMU_IO -c 'read -P 42 0 512' "$TEST_IMG" | _filter_qemu_io + + +# Taken from test 071 +echo +echo "=== Testing blkdebug ===" +echo + +_make_test_img $IMG_SIZE + +$QEMU_IO -c 'write -P 42 0x38000 512' "$TEST_IMG" | _filter_qemu_io + +# The "image.filename" part tests whether "a": { "b": "c" } and "a.b": "c" do +# the same (which they should). +$QEMU_IO -c 'read -P 42 0x38000 512' "json:{ + \"driver\": \"$IMGFMT\", + \"file\": { + \"driver\": \"blkdebug\", + \"inject-error\": [{ + \"event\": \"l2_load\" + }], + \"image.filename\": \"$TEST_IMG\" + } +}" | _filter_qemu_io + + +echo +echo "=== Testing qemu-img info output ===" +echo + +TEST_IMG="json:{\"driver\":\"qcow2\",\"file.filename\":\"$TEST_IMG\"}" _img_info + + +echo +echo "=== Testing option merging ===" +echo + +# Both options given directly and those given in the filename should be used +$QEMU_IO -c "open -o driver=qcow2 json:{\"file.filename\":\"$TEST_IMG\"}" \ + -c "info" 2>&1 | _filter_testdir | _filter_imgfmt + +# Options given directly should be prioritized over those given in the filename +$QEMU_IO -c "open -o driver=qcow2 json:{\"driver\":\"raw\",\"file.filename\":\"$TEST_IMG\"}" \ + -c "info" 2>&1 | _filter_testdir | _filter_imgfmt + + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/089.out b/tests/qemu-iotests/089.out new file mode 100644 index 000000000..4ca2f88e6 --- /dev/null +++ b/tests/qemu-iotests/089.out @@ -0,0 +1,50 @@ +QA output created by 089 + +=== Testing nested image formats === + +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 +wrote 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 512/512 bytes at offset 512 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 512/512 bytes at offset 1024 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 512 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 1024 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Pattern verification failed at offset 0, 512 bytes +read 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +=== Testing blkdebug === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +wrote 512/512 bytes at offset 229376 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read failed: Input/output error + +=== Testing qemu-img info output === + +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 64M (67108864 bytes) +cluster_size: 65536 + +=== Testing option merging === + +format name: IMGFMT +cluster size: 64 KiB +vm state offset: 512 MiB +Format specific information: + compat: 1.1 + lazy refcounts: false +format name: IMGFMT +cluster size: 64 KiB +vm state offset: 512 MiB +Format specific information: + compat: 1.1 + lazy refcounts: false +*** done diff --git a/tests/qemu-iotests/090 b/tests/qemu-iotests/090 new file mode 100755 index 000000000..8d032f811 --- /dev/null +++ b/tests/qemu-iotests/090 @@ -0,0 +1,61 @@ +#!/bin/bash +# +# Test for discarding compressed clusters on qcow2 images +# +# Copyright (C) 2014 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +# creator +owner=mreitz@redhat.com + +seq="$(basename $0)" +echo "QA output created by $seq" + +here="$PWD" +tmp=/tmp/$$ +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_supported_fmt qcow2 +_supported_proto file +_supported_os Linux + +IMG_SIZE=128K + +_make_test_img $IMG_SIZE + +$QEMU_IO -c 'write -c -P 42 0 64k' \ + -c 'write -c -P 23 64k 64k' \ + -c 'discard 64k 64k' \ + "$TEST_IMG" | _filter_qemu_io + +$QEMU_IO -c 'read -P 0 64k 64k' "$TEST_IMG" | _filter_qemu_io + +_check_test_img + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/090.out b/tests/qemu-iotests/090.out new file mode 100644 index 000000000..2df93e0d9 --- /dev/null +++ b/tests/qemu-iotests/090.out @@ -0,0 +1,12 @@ +QA output created by 090 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 +wrote 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 65536/65536 bytes at offset 65536 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +discard 65536/65536 bytes at offset 65536 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 65536/65536 bytes at offset 65536 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +No errors were found on the image. +*** done diff --git a/tests/qemu-iotests/091 b/tests/qemu-iotests/091 new file mode 100755 index 000000000..32bbd5697 --- /dev/null +++ b/tests/qemu-iotests/091 @@ -0,0 +1,107 @@ +#!/bin/bash +# +# Live migration test +# +# Performs a migration from one VM to another via monitor commands +# +# Copyright (C) 2014 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +# creator +owner=jcody@redhat.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +status=1 # failure is the default! + +MIG_FIFO="${TEST_DIR}/migrate" + +_cleanup() +{ + rm -f "${MIG_FIFO}" + _cleanup_qemu + _cleanup_test_img +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter +. ./common.qemu + +_supported_fmt qcow2 +_supported_proto file +_supported_os Linux +_default_cache_mode "none" +_supported_cache_modes "writethrough" "none" "writeback" + +size=1G + +_make_test_img $size + +mkfifo "${MIG_FIFO}" + +echo +echo === Starting QEMU VM1 === +echo + +qemu_comm_method="monitor" +_launch_qemu -drive file="${TEST_IMG}",cache=${CACHEMODE},id=disk +h1=$QEMU_HANDLE + +echo +echo === Starting QEMU VM2 === +echo +_launch_qemu -drive file="${TEST_IMG}",cache=${CACHEMODE},id=disk \ + -incoming "exec: cat '${MIG_FIFO}'" +h2=$QEMU_HANDLE + +echo +echo === VM 1: Migrate from VM1 to VM2 === +echo + +silent=yes +_send_qemu_cmd $h1 'qemu-io disk "write -P 0x22 0 4M"' "(qemu)" +echo "vm1: qemu-io disk write complete" +_send_qemu_cmd $h1 "migrate \"exec: cat > '${MIG_FIFO}'\"" "(qemu)" +echo "vm1: live migration started" +qemu_cmd_repeat=20 _send_qemu_cmd $h1 "info migrate" "completed" +echo "vm1: live migration completed" + +echo +echo === VM 2: Post-migration, write to disk, verify running === +echo + +_send_qemu_cmd $h2 'qemu-io disk "write 4M 1M"' "(qemu)" +echo "vm2: qemu-io disk write complete" +qemu_cmd_repeat=20 _send_qemu_cmd $h2 "info status" "running" +echo "vm2: qemu process running successfully" + +echo "vm2: flush io, and quit" +_send_qemu_cmd $h2 'qemu-io disk flush' "(qemu)" +_send_qemu_cmd $h2 'quit' "" + +echo "Check image pattern" +${QEMU_IO} -c "read -P 0x22 0 4M" "${TEST_IMG}" | _filter_testdir | _filter_qemu_io + +echo "Running 'qemu-img check -r all \$TEST_IMG'" +"${QEMU_IMG}" check -r all "${TEST_IMG}" 2>&1 | _filter_testdir | _filter_qemu + +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/091.out b/tests/qemu-iotests/091.out new file mode 100644 index 000000000..a2e012296 --- /dev/null +++ b/tests/qemu-iotests/091.out @@ -0,0 +1,28 @@ +QA output created by 091 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + +=== Starting QEMU VM1 === + + +=== Starting QEMU VM2 === + + +=== VM 1: Migrate from VM1 to VM2 === + +vm1: qemu-io disk write complete +vm1: live migration started +vm1: live migration completed + +=== VM 2: Post-migration, write to disk, verify running === + +vm2: qemu-io disk write complete +vm2: qemu process running successfully +vm2: flush io, and quit +Check image pattern +read 4194304/4194304 bytes at offset 0 +4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Running 'qemu-img check -r all $TEST_IMG' +No errors were found on the image. +80/16384 = 0.49% allocated, 0.00% fragmented, 0.00% compressed clusters +Image end offset: 5570560 +*** done diff --git a/tests/qemu-iotests/092 b/tests/qemu-iotests/092 new file mode 100755 index 000000000..a8c0c9ca2 --- /dev/null +++ b/tests/qemu-iotests/092 @@ -0,0 +1,98 @@ +#!/bin/bash +# +# qcow1 format input validation tests +# +# Copyright (C) 2014 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +# creator +owner=kwolf@redhat.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! + +_cleanup() +{ + rm -f $TEST_IMG.snap + _cleanup_test_img +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_supported_fmt qcow +_supported_proto generic +_supported_os Linux + +offset_backing_file_offset=8 +offset_backing_file_size=16 +offset_size=24 +offset_cluster_bits=32 +offset_l2_bits=33 + +echo +echo "== Invalid cluster size ==" +_make_test_img 64M +poke_file "$TEST_IMG" "$offset_cluster_bits" "\xff" +{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir +poke_file "$TEST_IMG" "$offset_cluster_bits" "\x1f" +{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir +poke_file "$TEST_IMG" "$offset_cluster_bits" "\x08" +{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir +poke_file "$TEST_IMG" "$offset_cluster_bits" "\x11" +{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir + +echo +echo "== Invalid L2 table size ==" +_make_test_img 64M +poke_file "$TEST_IMG" "$offset_l2_bits" "\xff" +{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir +poke_file "$TEST_IMG" "$offset_l2_bits" "\x05" +{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir +poke_file "$TEST_IMG" "$offset_l2_bits" "\x0e" +{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir + +# 1 << 0x1b = 2^31 / L2_CACHE_SIZE +poke_file "$TEST_IMG" "$offset_l2_bits" "\x1b" +{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir + +echo +echo "== Invalid size ==" +_make_test_img 64M +poke_file "$TEST_IMG" "$offset_size" "\xee\xee\xee\xee\xee\xee\xee\xee" +{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir +poke_file "$TEST_IMG" "$offset_size" "\x7f\xff\xff\xff\xff\xff\xff\xff" +{ $QEMU_IO -c "write 0 64M" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir + +echo +echo "== Invalid backing file length ==" +_make_test_img 64M +poke_file "$TEST_IMG" "$offset_backing_file_offset" "\x00\x00\x00\xff" +poke_file "$TEST_IMG" "$offset_backing_file_size" "\xff\xff\xff\xff" +{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir +poke_file "$TEST_IMG" "$offset_backing_file_size" "\x7f\xff\xff\xff" +{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/092.out b/tests/qemu-iotests/092.out new file mode 100644 index 000000000..496d8f0a6 --- /dev/null +++ b/tests/qemu-iotests/092.out @@ -0,0 +1,38 @@ +QA output created by 092 + +== Invalid cluster size == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k +no file open, try 'help open' +qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k +no file open, try 'help open' +qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k +no file open, try 'help open' +qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k +no file open, try 'help open' + +== Invalid L2 table size == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k +no file open, try 'help open' +qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k +no file open, try 'help open' +qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k +no file open, try 'help open' +qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k +no file open, try 'help open' + +== Invalid size == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +qemu-io: can't open device TEST_DIR/t.qcow: Image too large +no file open, try 'help open' +qemu-io: can't open device TEST_DIR/t.qcow: Image too large +no file open, try 'help open' + +== Invalid backing file length == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +qemu-io: can't open device TEST_DIR/t.qcow: Backing file name too long +no file open, try 'help open' +qemu-io: can't open device TEST_DIR/t.qcow: Backing file name too long +no file open, try 'help open' +*** done diff --git a/tests/qemu-iotests/095 b/tests/qemu-iotests/095 new file mode 100755 index 000000000..acc7dbf18 --- /dev/null +++ b/tests/qemu-iotests/095 @@ -0,0 +1,86 @@ +#!/bin/bash +# +# Test for commit of larger active layer +# +# This tests live snapshots of images on a running QEMU instance, using +# QMP commands. Both single disk snapshots, and transactional group +# snapshots are performed. +# +# Copyright (C) 2014 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# creator +owner=jcody@redhat.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_qemu + rm -f "${TEST_IMG}.base" "${TEST_IMG}.snp1" + _cleanup_test_img +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter +. ./common.qemu + +_supported_fmt qcow2 +_supported_proto file +_supported_os Linux + +size_smaller=5M +size_larger=100M + +_make_test_img $size_smaller +mv "${TEST_IMG}" "${TEST_IMG}.base" + +_make_test_img -b "${TEST_IMG}.base" $size_larger +mv "${TEST_IMG}" "${TEST_IMG}.snp1" + +_make_test_img -b "${TEST_IMG}.snp1" $size_larger + +echo +echo "=== Base image info before commit and resize ===" +$QEMU_IMG info "${TEST_IMG}.base" | _filter_testdir + +echo +echo === Running QEMU Live Commit Test === +echo + +qemu_comm_method="qmp" +_launch_qemu -drive file="${TEST_IMG}",if=virtio,id=test +h=$QEMU_HANDLE + +_send_qemu_cmd $h "{ 'execute': 'qmp_capabilities' }" "return" + +_send_qemu_cmd $h "{ 'execute': 'block-commit', + 'arguments': { 'device': 'test', + 'top': '"${TEST_IMG}.snp1"' } }" "BLOCK_JOB_COMPLETED" + +echo +echo "=== Base image info after commit and resize ===" +$QEMU_IMG info "${TEST_IMG}.base" | _filter_testdir + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/095.out b/tests/qemu-iotests/095.out new file mode 100644 index 000000000..5864ddac2 --- /dev/null +++ b/tests/qemu-iotests/095.out @@ -0,0 +1,31 @@ +QA output created by 095 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=5242880 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=104857600 backing_file='TEST_DIR/t.IMGFMT.base' +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=104857600 backing_file='TEST_DIR/t.IMGFMT.snp1' + +=== Base image info before commit and resize === +image: TEST_DIR/t.qcow2.base +file format: qcow2 +virtual size: 5.0M (5242880 bytes) +disk size: 196K +cluster_size: 65536 +Format specific information: + compat: 1.1 + lazy refcounts: false + +=== Running QEMU Live Commit Test === + +{"return": {}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "test", "len": 104857600, "offset": 104857600, "speed": 0, "type": "commit"}} + +=== Base image info after commit and resize === +image: TEST_DIR/t.qcow2.base +file format: qcow2 +virtual size: 100M (104857600 bytes) +disk size: 196K +cluster_size: 65536 +Format specific information: + compat: 1.1 + lazy refcounts: false +*** done diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check index e2ed5a95f..8ca40116d 100755 --- a/tests/qemu-iotests/check +++ b/tests/qemu-iotests/check @@ -34,22 +34,95 @@ timestamp=${TIMESTAMP:=false} # generic initialization iam=check +_init_error() +{ + echo "$iam: $1" >&2 + exit 1 +} + +if [ -L "$0" ] +then + # called from the build tree + source_iotests=$(dirname "$(readlink "$0")") + if [ -z "$source_iotests" ] + then + _init_error "failed to obtain source tree name from check symlink" + fi + source_iotests=$(cd "$source_iotests"; pwd) || _init_error "failed to enter source tree" + build_iotests=$PWD +else + # called from the source tree + source_iotests=$PWD + # this may be an in-tree build (note that in the following code we may not + # assume that it truly is and have to test whether the build results + # actually exist) + build_iotests=$PWD +fi + +build_root="$build_iotests/../.." + +if [ -x "$build_iotests/socket_scm_helper" ] +then + export SOCKET_SCM_HELPER="$build_iotests/socket_scm_helper" +fi + +# if ./qemu exists, it should be prioritized and will be chosen by common.config +if [[ -z "$QEMU_PROG" && ! -x './qemu' ]] +then + arch=$(uname -m 2> /dev/null) + + if [[ -n $arch && -x "$build_root/$arch-softmmu/qemu-system-$arch" ]] + then + export QEMU_PROG="$build_root/$arch-softmmu/qemu-system-$arch" + else + pushd "$build_root" > /dev/null + for binary in *-softmmu/qemu-system-* + do + if [ -x "$binary" ] + then + export QEMU_PROG="$build_root/$binary" + break + fi + done + popd > /dev/null + fi +fi + +if [[ -z $QEMU_IMG_PROG && -x "$build_root/qemu-img" && ! -x './qemu-img' ]] +then + export QEMU_IMG_PROG="$build_root/qemu-img" +fi + +if [[ -z $QEMU_IO_PROG && -x "$build_root/qemu-io" && ! -x './qemu-io' ]] +then + export QEMU_IO_PROG="$build_root/qemu-io" +fi + +if [[ -z $QEMU_NBD_PROG && -x "$build_root/qemu-nbd" && ! -x './qemu-nbd' ]] +then + export QEMU_NBD_PROG="$build_root/qemu-nbd" +fi + +# we need common.env +if ! . "$build_iotests/common.env" +then + _init_error "failed to source common.env (make sure the qemu-iotests are run from tests/qemu-iotests in the build tree)" +fi + # we need common.config -if ! . ./common.config +if ! . "$source_iotests/common.config" then - echo "$iam: failed to source common.config" - exit 1 + _init_error "failed to source common.config" fi # we need common.rc -if ! . ./common.rc +if ! . "$source_iotests/common.rc" then - echo "check: failed to source common.rc" - exit 1 + _init_error "failed to source common.rc" fi # we need common -. ./common +. "$source_iotests/common" #if [ `id -u` -ne 0 ] #then @@ -194,7 +267,7 @@ do echo " - expunged" rm -f $seq.out.bad echo "/^$seq\$/d" >>$tmp.expunged - elif [ ! -f $seq ] + elif [ ! -f "$source_iotests/$seq" ] then echo " - no such test?" echo "/^$seq\$/d" >>$tmp.expunged @@ -215,9 +288,16 @@ do start=`_wallclock` $timestamp && echo -n " ["`date "+%T"`"]" - [ ! -x $seq ] && chmod u+x $seq # ensure we can run it + + if [ "$(head -n 1 "$source_iotests/$seq")" == "#!/usr/bin/env python" ]; then + run_command="$PYTHON $seq" + else + run_command="./$seq" + fi + export OUTPUT_DIR=$PWD + (cd "$source_iotests"; MALLOC_PERTURB_=${MALLOC_PERTURB_:-$(($RANDOM % 255 + 1))} \ - ./$seq >$tmp.out 2>&1 + $run_command >$tmp.out 2>&1) sts=$? $timestamp && _timestamp stop=`_wallclock` @@ -242,17 +322,17 @@ do err=true fi - reference=$seq.out + reference="$source_iotests/$seq.out" if [ "$CACHEMODE" = "none" ]; then - [ -f $seq.out.nocache ] && reference=$seq.out.nocache + [ -f "$source_iotests/$seq.out.nocache" ] && reference="$source_iotests/$seq.out.nocache" fi - if [ ! -f $reference ] + if [ ! -f "$reference" ] then echo " - no qualified output" err=true else - if diff -w $reference $tmp.out >/dev/null 2>&1 + if diff -w "$reference" $tmp.out >/dev/null 2>&1 then echo "" if $err @@ -264,7 +344,7 @@ do else echo " - output mismatch (see $seq.out.bad)" mv $tmp.out $seq.out.bad - $diff -w $reference $seq.out.bad + $diff -w "$reference" $seq.out.bad err=true fi fi diff --git a/tests/qemu-iotests/common b/tests/qemu-iotests/common index 0aaf84d01..e4083f421 100644 --- a/tests/qemu-iotests/common +++ b/tests/qemu-iotests/common @@ -25,8 +25,7 @@ _setenvironment() export MSGVERB } -here=`pwd` -rm -f $here/$iam.out +rm -f "$OUTPUT_DIR/$iam.out" _setenvironment check=${check-true} @@ -59,7 +58,7 @@ do if $group then # arg after -g - group_list=`sed -n <group -e 's/$/ /' -e "/^[0-9][0-9][0-9].* $r /"'{ + group_list=`sed -n <"$source_iotests/group" -e 's/$/ /' -e "/^[0-9][0-9][0-9].* $r /"'{ s/ .*//p }'` if [ -z "$group_list" ] @@ -84,7 +83,7 @@ s/ .*//p then # arg after -x [ ! -s $tmp.list ] && ls [0-9][0-9][0-9] [0-9][0-9][0-9][0-9] >$tmp.list 2>/dev/null - group_list=`sed -n <group -e 's/$/ /' -e "/^[0-9][0-9][0-9].* $r /"'{ + group_list=`sed -n <"$source_iotests/group" -e 's/$/ /' -e "/^[0-9][0-9][0-9].* $r /"'{ s/ .*//p }'` if [ -z "$group_list" ] @@ -366,7 +365,7 @@ testlist options BEGIN { for (t='$start'; t<='$end'; t++) printf "%03d\n",t }' \ | while read id do - if grep -s "^$id " group >/dev/null + if grep -s "^$id " "$source_iotests/group" >/dev/null then # in group file ... OK echo $id >>$tmp.list @@ -402,7 +401,7 @@ else touch $tmp.list else # no test numbers, do everything from group file - sed -n -e '/^[0-9][0-9][0-9]*/s/[ ].*//p' <group >$tmp.list + sed -n -e '/^[0-9][0-9][0-9]*/s/[ ].*//p' <"$source_iotests/group" >$tmp.list fi fi diff --git a/tests/qemu-iotests/common.config b/tests/qemu-iotests/common.config index d90a8bca8..bd6790be6 100644 --- a/tests/qemu-iotests/common.config +++ b/tests/qemu-iotests/common.config @@ -126,7 +126,7 @@ fi export TEST_DIR if [ -z "$SAMPLE_IMG_DIR" ]; then - SAMPLE_IMG_DIR=`pwd`/sample_images + SAMPLE_IMG_DIR="$source_iotests/sample_images" fi if [ ! -d "$SAMPLE_IMG_DIR" ]; then diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter index 776985d15..a04df7f6d 100644 --- a/tests/qemu-iotests/common.filter +++ b/tests/qemu-iotests/common.filter @@ -150,6 +150,7 @@ _filter_win32() _filter_qemu_io() { _filter_win32 | sed -e "s/[0-9]* ops\; [0-9/:. sec]* ([0-9/.inf]* [EPTGMKiBbytes]*\/sec and [0-9/.inf]* ops\/sec)/X ops\; XX:XX:XX.X (XXX YYY\/sec and XXX ops\/sec)/" \ + -e "s/: line [0-9][0-9]*: *[0-9][0-9]*\( Aborted\)/:\1/" \ -e "s/qemu-io> //g" } diff --git a/tests/qemu-iotests/common.qemu b/tests/qemu-iotests/common.qemu new file mode 100644 index 000000000..ee7ebb4c1 --- /dev/null +++ b/tests/qemu-iotests/common.qemu @@ -0,0 +1,200 @@ +#!/bin/bash +# +# This allows for launching of multiple QEMU instances, with independent +# communication possible to each instance. +# +# Each instance can choose, at launch, to use either the QMP or the +# HMP (monitor) interface. +# +# All instances are cleaned up via _cleanup_qemu, including killing the +# running qemu instance. +# +# Copyright (C) 2014 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +QEMU_COMM_TIMEOUT=10 + +QEMU_FIFO_IN="${TEST_DIR}/qmp-in-$$" +QEMU_FIFO_OUT="${TEST_DIR}/qmp-out-$$" + +QEMU_PID= +_QEMU_HANDLE=0 +QEMU_HANDLE=0 + +# If bash version is >= 4.1, these will be overwritten and dynamic +# file descriptor values assigned. +_out_fd=3 +_in_fd=4 + +# Wait for expected QMP response from QEMU. Will time out +# after 10 seconds, which counts as failure. +# +# Override QEMU_COMM_TIMEOUT for a timeout different than the +# default 10 seconds +# +# $1: The handle to use +# $2+ All remaining arguments comprise the string to search for +# in the response. +# +# If $silent is set to anything but an empty string, then +# response is not echoed out. +function _timed_wait_for() +{ + local h=${1} + shift + + QEMU_STATUS[$h]=0 + while read -t ${QEMU_COMM_TIMEOUT} resp <&${QEMU_OUT[$h]} + do + if [ -z "${silent}" ]; then + echo "${resp}" | _filter_testdir | _filter_qemu \ + | _filter_qemu_io | _filter_qmp + fi + grep -q "${*}" < <(echo ${resp}) + if [ $? -eq 0 ]; then + return + fi + done + QEMU_STATUS[$h]=-1 + if [ -z "${qemu_error_no_exit}" ]; then + echo "Timeout waiting for ${*} on handle ${h}" + exit 1 # Timeout means the test failed + fi +} + + +# Sends QMP or HMP command to QEMU, and waits for the expected response +# +# $1: QEMU handle to use +# $2: String of the QMP command to send +# ${@: -1} (Last string passed) +# String that the QEMU response should contain. If it is a null +# string, do not wait for a response +# +# Set qemu_cmd_repeat to the number of times to repeat the cmd +# until either timeout, or a response. If it is not set, or <=0, +# then the command is only sent once. +# +# If $qemu_error_no_exit is set, then even if the expected response +# is not seen, we will not exit. $QEMU_STATUS[$1] will be set it -1 in +# that case. +function _send_qemu_cmd() +{ + local h=${1} + local count=1 + local cmd= + local use_error=${qemu_error_no_exit} + shift + + if [ ${qemu_cmd_repeat} -gt 0 ] 2>/dev/null; then + count=${qemu_cmd_repeat} + use_error="no" + fi + # This array element extraction is done to accommodate pathnames with spaces + cmd=${@: 1:${#@}-1} + shift $(($# - 1)) + + while [ ${count} -gt 0 ] + do + echo "${cmd}" >&${QEMU_IN[${h}]} + if [ -n "${1}" ]; then + qemu_error_no_exit=${use_error} _timed_wait_for ${h} "${1}" + if [ ${QEMU_STATUS[$h]} -eq 0 ]; then + return + fi + fi + let count--; + done + if [ ${QEMU_STATUS[$h]} -ne 0 ] && [ -z "${qemu_error_no_exit}" ]; then + echo "Timeout waiting for ${1} on handle ${h}" + exit 1 #Timeout means the test failed + fi +} + + +# Launch a QEMU process. +# +# Input parameters: +# $qemu_comm_method: set this variable to 'monitor' (case insensitive) +# to use the QEMU HMP monitor for communication. +# Otherwise, the default of QMP is used. +# Returns: +# $QEMU_HANDLE: set to a handle value to communicate with this QEMU instance. +# +function _launch_qemu() +{ + local comm= + local fifo_out= + local fifo_in= + + if (shopt -s nocasematch; [[ "${qemu_comm_method}" == "monitor" ]]) + then + comm="-monitor stdio" + else + local qemu_comm_method="qmp" + comm="-monitor none -qmp stdio" + fi + + fifo_out=${QEMU_FIFO_OUT}_${_QEMU_HANDLE} + fifo_in=${QEMU_FIFO_IN}_${_QEMU_HANDLE} + mkfifo "${fifo_out}" + mkfifo "${fifo_in}" + + "${QEMU}" -nographic -serial none ${comm} -machine accel=qtest "${@}" 2>&1 \ + >"${fifo_out}" \ + <"${fifo_in}" & + QEMU_PID[${_QEMU_HANDLE}]=$! + + if [[ "${BASH_VERSINFO[0]}" -ge "5" || + ("${BASH_VERSINFO[0]}" -ge "4" && "${BASH_VERSINFO[1]}" -ge "1") ]] + then + # bash >= 4.1 required for automatic fd + exec {_out_fd}<"${fifo_out}" + exec {_in_fd}>"${fifo_in}" + else + let _out_fd++ + let _in_fd++ + eval "exec ${_out_fd}<'${fifo_out}'" + eval "exec ${_in_fd}>'${fifo_in}'" + fi + + QEMU_OUT[${_QEMU_HANDLE}]=${_out_fd} + QEMU_IN[${_QEMU_HANDLE}]=${_in_fd} + QEMU_STATUS[${_QEMU_HANDLE}]=0 + + if [ "${qemu_comm_method}" == "qmp" ] + then + # Don't print response, since it has version information in it + silent=yes _timed_wait_for ${_QEMU_HANDLE} "capabilities" + fi + QEMU_HANDLE=${_QEMU_HANDLE} + let _QEMU_HANDLE++ +} + + +# Silenty kills the QEMU process +function _cleanup_qemu() +{ + # QEMU_PID[], QEMU_IN[], QEMU_OUT[] all use same indices + for i in "${!QEMU_OUT[@]}" + do + kill -KILL ${QEMU_PID[$i]} 2>/dev/null + wait ${QEMU_PID[$i]} 2>/dev/null # silent kill + rm -f "${QEMU_FIFO_IN}_${i}" "${QEMU_FIFO_OUT}_${i}" + eval "exec ${QEMU_IN[$i]}<&-" # close file descriptors + eval "exec ${QEMU_OUT[$i]}<&-" + done +} diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index 7f00883ca..e0ea7e3a7 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -178,10 +178,10 @@ _rm_test_img() local img=$1 if [ "$IMGFMT" = "vmdk" ]; then # Remove all the extents for vmdk - $QEMU_IMG info $img 2>/dev/null | grep 'filename:' | cut -f 2 -d: \ + "$QEMU_IMG" info "$img" 2>/dev/null | grep 'filename:' | cut -f 2 -d: \ | xargs -I {} rm -f "{}" fi - rm -f $img + rm -f "$img" } _cleanup_test_img() @@ -318,9 +318,9 @@ _do() status=1; exit fi - (eval "echo '---' \"$_cmd\"") >>$here/$seq.full + (eval "echo '---' \"$_cmd\"") >>"$OUTPUT_DIR/$seq.full" (eval "$_cmd") >$tmp._out 2>&1; ret=$? - cat $tmp._out >>$here/$seq.full + cat $tmp._out >>"$OUTPUT_DIR/$seq.full" if [ $# -eq 2 ]; then if [ $ret -eq 0 ]; then echo "done" @@ -344,7 +344,7 @@ _do() # _notrun() { - echo "$*" >$seq.notrun + echo "$*" >"$OUTPUT_DIR/$seq.notrun" echo "$seq not run: $*" status=0 exit @@ -354,7 +354,7 @@ _notrun() # _fail() { - echo "$*" | tee -a $here/$seq.full + echo "$*" | tee -a "$OUTPUT_DIR/$seq.full" echo "(see $seq.full for details)" status=1 exit 1 diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 864643d25..6e67f6126 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -7,16 +7,16 @@ # # test-group association ... one line per test # -001 rw auto +001 rw auto quick 002 rw auto quick 003 rw auto 004 rw auto quick -005 img auto +005 img auto quick 006 img auto 007 snapshot auto -008 rw auto -009 rw auto -010 rw auto +008 rw auto quick +009 rw auto quick +010 rw auto quick 011 rw auto quick 012 auto quick 013 rw auto @@ -24,36 +24,36 @@ 015 rw snapshot auto 016 rw auto quick 017 rw backing auto quick -018 rw backing auto +018 rw backing auto quick 019 rw backing auto quick 020 rw backing auto quick -021 io auto +021 io auto quick 022 rw snapshot auto 023 rw auto 024 rw backing auto quick 025 rw auto quick 026 rw blkdbg auto 027 rw auto quick -028 rw backing auto +028 rw backing auto quick 029 rw auto quick 030 rw auto backing 031 rw auto quick -032 rw auto +032 rw auto quick 033 rw auto quick -034 rw auto backing +034 rw auto backing quick 035 rw auto quick 036 rw auto quick -037 rw auto backing -038 rw auto backing -039 rw auto +037 rw auto backing quick +038 rw auto backing quick +039 rw auto quick 040 rw auto 041 rw auto backing 042 rw auto quick 043 rw auto backing 044 rw auto -045 rw auto -046 rw auto aio -047 rw auto +045 rw auto quick +046 rw auto aio quick +047 rw auto quick 048 img auto quick 049 rw auto 050 rw auto backing quick @@ -71,27 +71,32 @@ 062 rw auto quick 063 rw auto quick 064 rw auto quick -065 rw auto +065 rw auto quick 066 rw auto quick -067 rw auto -068 rw auto +067 rw auto quick +068 rw auto quick 069 rw auto quick 070 rw auto quick -071 rw auto +071 rw auto quick 072 rw auto quick 073 rw auto quick 074 rw auto quick -075 rw auto +075 rw auto quick 076 auto 077 rw auto quick -078 rw auto +078 rw auto quick 079 rw auto 080 rw auto -081 rw auto +081 rw auto quick 082 rw auto quick 083 rw auto -084 img auto +084 img auto quick 085 rw auto 086 rw auto quick -087 rw auto -088 rw auto +087 rw auto quick +088 rw auto quick +089 rw auto quick +090 rw auto quick +091 rw auto quick +092 rw auto quick +095 rw auto quick diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index e4fa9af71..39a4cfcf4 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -37,6 +37,7 @@ qemu_args = os.environ.get('QEMU', 'qemu').strip().split(' ') imgfmt = os.environ.get('IMGFMT', 'raw') imgproto = os.environ.get('IMGPROTO', 'file') test_dir = os.environ.get('TEST_DIR', '/var/tmp') +output_dir = os.environ.get('OUTPUT_DIR', '.') cachemode = os.environ.get('CACHEMODE') socket_scm_helper = os.environ.get('SOCKET_SCM_HELPER', 'socket_scm_helper') @@ -257,7 +258,7 @@ class QMPTestCase(unittest.TestCase): self.assert_no_active_block_jobs() return result - def wait_until_completed(self, drive='drive0'): + def wait_until_completed(self, drive='drive0', check_offset=True): '''Wait for a block job to finish, returning the event''' completed = False while not completed: @@ -265,7 +266,8 @@ class QMPTestCase(unittest.TestCase): if event['event'] == 'BLOCK_JOB_COMPLETED': self.assert_qmp(event, 'data/device', drive) self.assert_qmp_absent(event, 'data/error') - self.assert_qmp(event, 'data/offset', self.image_len) + if check_offset: + self.assert_qmp(event, 'data/offset', self.image_len) self.assert_qmp(event, 'data/len', self.image_len) completed = True @@ -277,7 +279,7 @@ def notrun(reason): # Each test in qemu-iotests has a number ("seq") seq = os.path.basename(sys.argv[0]) - open('%s.notrun' % seq, 'wb').write(reason + '\n') + open('%s/%s.notrun' % (output_dir, seq), 'wb').write(reason + '\n') print '%s not run: %s' % (seq, reason) sys.exit(0) diff --git a/tests/qemu-iotests/qcow2.py b/tests/qemu-iotests/qcow2.py index 44a2b4564..205859696 100755 --- a/tests/qemu-iotests/qcow2.py +++ b/tests/qemu-iotests/qcow2.py @@ -176,6 +176,10 @@ def cmd_add_header_ext(fd, magic, data): h.extensions.append(QcowHeaderExtension.create(magic, data)) h.update(fd) +def cmd_add_header_ext_stdio(fd, magic): + data = sys.stdin.read() + cmd_add_header_ext(fd, magic, data) + def cmd_del_header_ext(fd, magic): try: magic = int(magic, 0) @@ -220,11 +224,12 @@ def cmd_set_feature_bit(fd, group, bit): h.update(fd) cmds = [ - [ 'dump-header', cmd_dump_header, 0, 'Dump image header and header extensions' ], - [ 'set-header', cmd_set_header, 2, 'Set a field in the header'], - [ 'add-header-ext', cmd_add_header_ext, 2, 'Add a header extension' ], - [ 'del-header-ext', cmd_del_header_ext, 1, 'Delete a header extension' ], - [ 'set-feature-bit', cmd_set_feature_bit, 2, 'Set a feature bit'], + [ 'dump-header', cmd_dump_header, 0, 'Dump image header and header extensions' ], + [ 'set-header', cmd_set_header, 2, 'Set a field in the header'], + [ 'add-header-ext', cmd_add_header_ext, 2, 'Add a header extension' ], + [ 'add-header-ext-stdio', cmd_add_header_ext_stdio, 1, 'Add a header extension, data from stdin' ], + [ 'del-header-ext', cmd_del_header_ext, 1, 'Delete a header extension' ], + [ 'set-feature-bit', cmd_set_feature_bit, 2, 'Set a feature bit'], ] def main(filename, cmd, args): diff --git a/tests/qemu-iotests/sample_images/test-disk2vhd.vhdx.bz2 b/tests/qemu-iotests/sample_images/test-disk2vhd.vhdx.bz2 Binary files differnew file mode 100644 index 000000000..2891c9a6d --- /dev/null +++ b/tests/qemu-iotests/sample_images/test-disk2vhd.vhdx.bz2 diff --git a/tests/qom-test.c b/tests/qom-test.c index 6d9a00b44..4246382d3 100644 --- a/tests/qom-test.c +++ b/tests/qom-test.c @@ -44,7 +44,7 @@ static bool is_blacklisted(const char *arch, const char *mach) return false; } -static void test_properties(const char *path) +static void test_properties(const char *path, bool recurse) { char *child_path; QDict *response, *tuple; @@ -53,24 +53,31 @@ static void test_properties(const char *path) g_test_message("Obtaining properties of %s", path); response = qmp("{ 'execute': 'qom-list'," - " 'arguments': { 'path': '%s' } }", path); + " 'arguments': { 'path': %s } }", path); g_assert(response); + if (!recurse) { + return; + } + g_assert(qdict_haskey(response, "return")); list = qobject_to_qlist(qdict_get(response, "return")); QLIST_FOREACH_ENTRY(list, entry) { tuple = qobject_to_qdict(qlist_entry_obj(entry)); - if (strstart(qdict_get_str(tuple, "type"), "child<", NULL)) { + bool is_child = strstart(qdict_get_str(tuple, "type"), "child<", NULL); + bool is_link = strstart(qdict_get_str(tuple, "type"), "link<", NULL); + + if (is_child || is_link) { child_path = g_strdup_printf("%s/%s", path, qdict_get_str(tuple, "name")); - test_properties(child_path); + test_properties(child_path, is_child); g_free(child_path); } else { const char *prop = qdict_get_str(tuple, "name"); g_test_message("Testing property %s.%s", path, prop); response = qmp("{ 'execute': 'qom-get'," - " 'arguments': { 'path': '%s'," - " 'property': '%s' } }", + " 'arguments': { 'path': %s," + " 'property': %s } }", path, prop); /* qom-get may fail but should not, e.g., segfault. */ g_assert(response); @@ -87,7 +94,7 @@ static void test_machine(gconstpointer data) args = g_strdup_printf("-machine %s", machine); qtest_start(args); - test_properties("/machine"); + test_properties("/machine", true); response = qmp("{ 'execute': 'quit' }"); g_assert(qdict_haskey(response, "return")); diff --git a/tests/tcg/Makefile b/tests/tcg/Makefile index 24e3154ca..89e3342f3 100644 --- a/tests/tcg/Makefile +++ b/tests/tcg/Makefile @@ -81,10 +81,8 @@ run-test_path: test_path # rules to compile tests test_path: test_path.o - $(CC_I386) $(LDFLAGS) -o $@ $^ $(LIBS) test_path.o: test_path.c - $(CC_I386) $(QEMU_INCLUDES) $(GLIB_CFLAGS) $(CFLAGS) -c -o $@ $^ hello-i386: hello-i386.c $(CC_I386) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $< diff --git a/tests/tcg/lm32/Makefile b/tests/tcg/lm32/Makefile index 8e5d40545..57e7363b2 100644 --- a/tests/tcg/lm32/Makefile +++ b/tests/tcg/lm32/Makefile @@ -3,7 +3,7 @@ CROSS=lm32-elf- SIM = qemu-system-lm32 -SIMFLAGS = -M lm32-evr -nographic -device lm32-sys -net none -kernel +SIMFLAGS = -M lm32-evr -nographic -semihosting -net none -kernel CC = $(CROSS)gcc AS = $(CROSS)as @@ -18,6 +18,7 @@ LDFLAGS = -T$(TSRC_PATH)/linker.ld ASFLAGS += -Wa,-I,$(TSRC_PATH)/ CRT = crt.o +HELPER = helper.o TESTCASES += test_add.tst TESTCASES += test_addi.tst TESTCASES += test_and.tst @@ -91,15 +92,15 @@ all: build %.o: $(TSRC_PATH)/%.S $(AS) $(ASFLAGS) -c $< -o $@ -%.tst: %.o $(TSRC_PATH)/macros.inc $(CRT) - $(LD) $(LDFLAGS) $(NOSTDFLAGS) $(CRT) $< -o $@ +%.tst: %.o $(TSRC_PATH)/macros.inc $(CRT) $(HELPER) + $(LD) $(LDFLAGS) $(NOSTDFLAGS) $(CRT) $(HELPER) $< -o $@ -build: $(CRT) $(TESTCASES) +build: $(TESTCASES) check: $(TESTCASES:test_%.tst=check_%) -check_%: test_%.tst $(CRT) $(SYS) - $(SIM) $(SIMFLAGS) $< +check_%: test_%.tst + @$(SIM) $(SIMFLAGS) $< clean: - $(RM) -fr $(TESTCASES) $(CRT) + $(RM) -fr $(TESTCASES) $(CRT) $(HELPER) diff --git a/tests/tcg/lm32/crt.S b/tests/tcg/lm32/crt.S index 5f9cfd95d..fc437a3de 100644 --- a/tests/tcg/lm32/crt.S +++ b/tests/tcg/lm32/crt.S @@ -8,9 +8,9 @@ _reset_handler: ori r1, r1, lo(_start) wcsr eba, r1 wcsr deba, r1 + mvhi sp, hi(_fstack) + ori sp, sp, lo(_fstack) bi _main - nop - nop _breakpoint_handler: ori r25, r25, 1 diff --git a/tests/tcg/lm32/helper.S b/tests/tcg/lm32/helper.S new file mode 100644 index 000000000..3351d41e8 --- /dev/null +++ b/tests/tcg/lm32/helper.S @@ -0,0 +1,65 @@ +.text +.global _start, _write, _exit +.global _tc_fail, _tc_pass + +_write: + addi sp, sp, -4 + sw (sp+4), r8 + mvi r8, 5 + scall + lw r8, (sp+4) + addi sp, sp, 4 + ret + +_exit: + mvi r8, 1 + scall +1: + bi 1b + +_tc_pass: +.data +1: + .ascii "OK\n" +2: +.text + addi sp, sp, -16 + sw (sp+4), ra + sw (sp+8), r1 + sw (sp+12), r2 + sw (sp+16), r3 + mvi r1, 1 + mvhi r2, hi(1b) + ori r2, r2, lo(1b) + mvi r3, (2b - 1b) + calli _write + lw r3, (sp+16) + lw r2, (sp+12) + lw r1, (sp+8) + lw ra, (sp+4) + addi sp, sp, 16 + ret + +_tc_fail: +.data +1: + .ascii "FAILED\n" +2: +.text + addi sp, sp, -16 + sw (sp+4), ra + sw (sp+8), r1 + sw (sp+12), r2 + sw (sp+16), r3 + sw (sp+4), ra + mvi r1, 1 + mvhi r2, hi(1b) + ori r2, r2, lo(1b) + mvi r3, (2b - 1b) + calli _write + lw r3, (sp+16) + lw r2, (sp+12) + lw r1, (sp+8) + lw ra, (sp+4) + addi sp, sp, 16 + ret diff --git a/tests/tcg/lm32/macros.inc b/tests/tcg/lm32/macros.inc index 367c7c50d..360ad53c9 100644 --- a/tests/tcg/lm32/macros.inc +++ b/tests/tcg/lm32/macros.inc @@ -1,12 +1,26 @@ +.equ MAX_TESTNAME_LEN, 32 .macro test_name name .data tn_\name: - .asciz "\name" + .ascii "\name" + .space MAX_TESTNAME_LEN - (. - tn_\name), ' ' .text - mvhi r13, hi(tn_\name) - ori r13, r13, lo(tn_\name) - sw (r12+8), r13 + .global \name +\name: + addi sp, sp, -12 + sw (sp+4), r1 + sw (sp+8), r2 + sw (sp+12), r3 + mvi r1, 1 + mvhi r2, hi(tn_\name) + ori r2, r2, lo(tn_\name) + mvi r3, MAX_TESTNAME_LEN + calli _write + lw r3, (sp+12) + lw r2, (sp+8) + lw r1, (sp+4) + addi sp, sp, 12 .endm .macro load reg val @@ -15,13 +29,12 @@ tn_\name: .endm .macro tc_pass - mvi r13, 0 - sw (r12+4), r13 + calli _tc_pass .endm .macro tc_fail - mvi r13, 1 - sw (r12+4), r13 + addi r12, r12, 1 + calli _tc_fail .endm .macro check_r3 val @@ -63,14 +76,12 @@ tn_\name: .global _main .text _main: - mvhi r12, hi(0xffff0000) # base address of test block - ori r12, r12, lo(0xffff0000) + mvi r12, 0 .endm .macro end - sw (r12+0), r0 -1: - bi 1b + mv r1, r12 + calli _exit .endm # base + diff --git a/tests/tcg/lm32/test_lb.S b/tests/tcg/lm32/test_lb.S index f84d21ead..d677eea4c 100644 --- a/tests/tcg/lm32/test_lb.S +++ b/tests/tcg/lm32/test_lb.S @@ -8,10 +8,12 @@ lb r3, (r1+0) check_r3 0x7e test_name LB_2 +load r1 data lb r3, (r1+1) check_r3 0x7f test_name LB_3 +load r1 data lb r3, (r1+-1) check_r3 0x7d @@ -21,10 +23,12 @@ lb r3, (r1+0) check_r3 0xfffffffe test_name LB_5 +load r1 data_msb lb r3, (r1+1) check_r3 0xffffffff test_name LB_6 +load r1 data_msb lb r3, (r1+-1) check_r3 0xfffffffd diff --git a/tests/tcg/lm32/test_lbu.S b/tests/tcg/lm32/test_lbu.S index 4c1786ad7..dc5d5f67d 100644 --- a/tests/tcg/lm32/test_lbu.S +++ b/tests/tcg/lm32/test_lbu.S @@ -8,10 +8,12 @@ lbu r3, (r1+0) check_r3 0x7e test_name LBU_2 +load r1 data lbu r3, (r1+1) check_r3 0x7f test_name LBU_3 +load r1 data lbu r3, (r1+-1) check_r3 0x7d @@ -21,10 +23,12 @@ lbu r3, (r1+0) check_r3 0xfe test_name LBU_5 +load r1 data_msb lbu r3, (r1+1) check_r3 0xff test_name LBU_6 +load r1 data_msb lbu r3, (r1+-1) check_r3 0xfd diff --git a/tests/tcg/lm32/test_lh.S b/tests/tcg/lm32/test_lh.S index e57d9e35c..397996bdd 100644 --- a/tests/tcg/lm32/test_lh.S +++ b/tests/tcg/lm32/test_lh.S @@ -8,10 +8,12 @@ lh r3, (r1+0) check_r3 0x7e7f test_name LH_2 +load r1 data lh r3, (r1+2) check_r3 0x7071 test_name LH_3 +load r1 data lh r3, (r1+-2) check_r3 0x7c7d @@ -21,10 +23,12 @@ lh r3, (r1+0) check_r3 0xfffffeff test_name LH_5 +load r1 data_msb lh r3, (r1+2) check_r3 0xfffff0f1 test_name LH_6 +load r1 data_msb lh r3, (r1+-2) check_r3 0xfffffcfd diff --git a/tests/tcg/lm32/test_lhu.S b/tests/tcg/lm32/test_lhu.S index e648775d9..8de7c5256 100644 --- a/tests/tcg/lm32/test_lhu.S +++ b/tests/tcg/lm32/test_lhu.S @@ -8,10 +8,12 @@ lhu r3, (r1+0) check_r3 0x7e7f test_name LHU_2 +load r1 data lhu r3, (r1+2) check_r3 0x7071 test_name LHU_3 +load r1 data lhu r3, (r1+-2) check_r3 0x7c7d @@ -21,10 +23,12 @@ lhu r3, (r1+0) check_r3 0xfeff test_name LHU_5 +load r1 data_msb lhu r3, (r1+2) check_r3 0xf0f1 test_name LHU_6 +load r1 data_msb lhu r3, (r1+-2) check_r3 0xfcfd diff --git a/tests/tcg/lm32/test_lw.S b/tests/tcg/lm32/test_lw.S index f8c919d2b..996e5f8c8 100644 --- a/tests/tcg/lm32/test_lw.S +++ b/tests/tcg/lm32/test_lw.S @@ -8,10 +8,12 @@ lw r3, (r1+0) check_r3 0x7e7f7071 test_name LW_2 +load r1 data lw r3, (r1+4) check_r3 0x72737475 test_name LW_3 +load r1 data lw r3, (r1+-4) check_r3 0x7a7b7c7d diff --git a/tests/tcg/lm32/test_sb.S b/tests/tcg/lm32/test_sb.S index 89e39d621..b15a89d34 100644 --- a/tests/tcg/lm32/test_sb.S +++ b/tests/tcg/lm32/test_sb.S @@ -9,11 +9,13 @@ sb (r1+0), r2 check_mem data 0xaa000000 test_name SB_2 +load r1 data load r2 0xf0f1f2bb sb (r1+1), r2 check_mem data 0xaabb0000 test_name SB_3 +load r1 data load r2 0xf0f1f2cc sb (r1+-1), r2 check_mem data0 0x000000cc diff --git a/tests/tcg/lm32/test_scall.S b/tests/tcg/lm32/test_scall.S index b442e3237..46032f841 100644 --- a/tests/tcg/lm32/test_scall.S +++ b/tests/tcg/lm32/test_scall.S @@ -5,6 +5,10 @@ start test_name SCALL_1 mvi r1, 1 wcsr IE, r1 +# we are running in a semi hosted environment +# therefore we have to set r8 to some unused system +# call +mvi r8, 0 insn: scall check_excp 64 diff --git a/tests/tcg/lm32/test_sh.S b/tests/tcg/lm32/test_sh.S index ea8b3f206..bba10224f 100644 --- a/tests/tcg/lm32/test_sh.S +++ b/tests/tcg/lm32/test_sh.S @@ -9,11 +9,13 @@ sh (r1+0), r2 check_mem data 0xaaaa0000 test_name SH_2 +load r1 data load r2 0xf0f1bbbb sh (r1+2), r2 check_mem data 0xaaaabbbb test_name SH_3 +load r1 data load r2 0xf0f1cccc sh (r1+-2), r2 check_mem data0 0x0000cccc diff --git a/tests/tcg/lm32/test_sw.S b/tests/tcg/lm32/test_sw.S index d1fdadce6..2b1c017e7 100644 --- a/tests/tcg/lm32/test_sw.S +++ b/tests/tcg/lm32/test_sw.S @@ -9,16 +9,19 @@ sw (r1+0), r2 check_mem data 0xaabbccdd test_name SW_2 +load r1 data load r2 0x00112233 sw (r1+4), r2 check_mem data1 0x00112233 test_name SW_3 +load r1 data load r2 0x44556677 sw (r1+-4), r2 check_mem data0 0x44556677 test_name SW_4 +load r1 data sw (r1+0), r1 lw r3, (r1+0) check_r3 data diff --git a/tests/tcg/test_path.c b/tests/tcg/test_path.c index f8dd36aab..1c29bce26 100644 --- a/tests/tcg/test_path.c +++ b/tests/tcg/test_path.c @@ -1,17 +1,10 @@ /* Test path override code */ -#define _GNU_SOURCE #include "config-host.h" #include "util/cutils.c" #include "util/hexdump.c" #include "util/iov.c" #include "util/path.c" #include "util/qemu-timer-common.c" -#include "trace/control.c" -#include "../trace/generated-events.c" -#ifdef CONFIG_TRACE_SIMPLE -#include "trace/simple.c" -#endif - #include <stdarg.h> #include <sys/stat.h> #include <fcntl.h> diff --git a/tests/tcg/xtensa/test_mmu.S b/tests/tcg/xtensa/test_mmu.S index 099031fd1..58c5bca30 100644 --- a/tests/tcg/xtensa/test_mmu.S +++ b/tests/tcg/xtensa/test_mmu.S @@ -4,16 +4,28 @@ test_suite mmu .purgem test_init -.macro test_init - movi a2, 0x00000004 - idtlb a2 - movi a2, 0x00100004 +.macro clean_tlb_way way, page_size, n_entries + movi a2, \way + movi a3, \page_size + movi a4, \n_entries + loop a4, 1f idtlb a2 - movi a2, 0x00200004 + iitlb a2 + add a2, a2, a3 +1: +.endm + +.macro test_init + clean_tlb_way 0, 0x00001000, 4 + clean_tlb_way 1, 0x00001000, 4 + clean_tlb_way 2, 0x00001000, 4 + clean_tlb_way 3, 0x00001000, 4 + clean_tlb_way 4, 0x00100000, 4 + movi a2, 0x00000007 idtlb a2 - movi a2, 0x00300004 + movi a2, 0x00000008 idtlb a2 - movi a2, 0x00000007 + movi a2, 0x00000009 idtlb a2 .endm @@ -508,4 +520,224 @@ test autoload_3_level_pt assert_sr exccause, 24 test_end +test cross_page_insn + set_vector kernel, 2f + + movi a2, 0x04000003 /* PPN */ + movi a3, 0x00007000 /* VPN */ + witlb a2, a3 + wdtlb a2, a3 + movi a3, 0x00008000 /* VPN */ + witlb a2, a3 + wdtlb a2, a3 + + movi a2, 0x00007fff + movi a3, 20f + movi a4, 21f + sub a4, a4, a3 + loop a4, 1f + l8ui a5, a3, 0 + s8i a5, a2, 0 + addi a2, a2, 1 + addi a3, a3, 1 +1: + movi a2, 0x00007fff + movi a3, 0x00008000 + /* DTLB: OK, ITLB: OK */ + jx a2 + + .begin no-transform +20: + l32i a2, a3, 0 + syscall +21: + .end no-transform + +2: + rsr a2, exccause + movi a3, 1 + assert eq, a2, a3 + rsr a2, epc1 + movi a3, 0x8002 + assert eq, a2, a3 + rsr a2, excsave1 + movi a3, 0x00007fff + assert ne, a2, a3 + + reset_ps + set_vector kernel, 3f + + movi a2, 0x0400000c /* PPN */ + movi a3, 0x00008000 /* VPN */ + wdtlb a2, a3 + movi a2, 0x00007fff + movi a3, 0x00008000 + /* DTLB: FAIL, ITLB: OK */ + jx a2 +3: + rsr a2, exccause + movi a3, 28 + assert eq, a2, a3 + rsr a2, epc1 + movi a3, 0x7fff + assert eq, a2, a3 + rsr a2, excsave1 + movi a3, 0x00007fff + assert eq, a2, a3 + + reset_ps + set_vector kernel, 4f + + movi a2, 0x0400000c /* PPN */ + movi a3, 0x00008000 /* VPN */ + witlb a2, a3 + movi a2, 0x04000003 /* PPN */ + wdtlb a2, a3 + movi a2, 0x00007fff + movi a3, 0x00008000 + /* DTLB: OK, ITLB: FAIL */ + jx a2 +4: + rsr a2, exccause + movi a3, 20 + assert eq, a2, a3 + rsr a2, epc1 + movi a3, 0x7fff + assert eq, a2, a3 + rsr a2, excsave1 + movi a3, 0x00007fff + assert eq, a2, a3 + + reset_ps + set_vector kernel, 5f + + movi a2, 0x0400000c /* PPN */ + movi a3, 0x00008000 /* VPN */ + wdtlb a2, a3 + movi a2, 0x00007fff + movi a3, 0x00008000 + /* DTLB: FAIL, ITLB: FAIL */ + jx a2 +5: + rsr a2, exccause + movi a3, 20 + assert eq, a2, a3 + rsr a2, epc1 + movi a3, 0x7fff + assert eq, a2, a3 + rsr a2, excsave1 + movi a3, 0x00007fff + assert eq, a2, a3 +test_end + +test cross_page_tb + set_vector kernel, 2f + + movi a2, 0x04000003 /* PPN */ + movi a3, 0x00007000 /* VPN */ + witlb a2, a3 + wdtlb a2, a3 + movi a3, 0x00008000 /* VPN */ + witlb a2, a3 + wdtlb a2, a3 + + movi a2, 0x00007ffd + movi a3, 20f + movi a4, 21f + sub a4, a4, a3 + loop a4, 1f + l8ui a5, a3, 0 + s8i a5, a2, 0 + addi a2, a2, 1 + addi a3, a3, 1 +1: + movi a2, 0x00007ffd + movi a3, 0x00008000 + /* DTLB: OK, ITLB: OK */ + jx a2 + + .begin no-transform +20: + l32i a2, a3, 0 + syscall +21: + .end no-transform + +2: + rsr a2, exccause + movi a3, 1 + assert eq, a2, a3 + rsr a2, epc1 + movi a3, 0x8000 + assert eq, a2, a3 + rsr a2, excsave1 + movi a3, 0x00007ffd + assert ne, a2, a3 + + reset_ps + set_vector kernel, 3f + + movi a2, 0x0400000c /* PPN */ + movi a3, 0x00008000 /* VPN */ + wdtlb a2, a3 + movi a2, 0x00007ffd + movi a3, 0x00008000 + /* DTLB: FAIL, ITLB: OK */ + jx a2 +3: + rsr a2, exccause + movi a3, 28 + assert eq, a2, a3 + rsr a2, epc1 + movi a3, 0x7ffd + assert eq, a2, a3 + rsr a2, excsave1 + movi a3, 0x00007ffd + assert eq, a2, a3 + + reset_ps + set_vector kernel, 4f + + movi a2, 0x0400000c /* PPN */ + movi a3, 0x00008000 /* VPN */ + witlb a2, a3 + movi a2, 0x04000003 /* PPN */ + wdtlb a2, a3 + movi a2, 0x00007ffd + movi a3, 0x00008000 + /* DTLB: OK, ITLB: FAIL */ + jx a2 +4: + rsr a2, exccause + movi a3, 20 + assert eq, a2, a3 + rsr a2, epc1 + movi a3, 0x8000 + assert eq, a2, a3 + rsr a2, excsave1 + movi a3, 0x00007ffd + assert ne, a2, a3 + + reset_ps + set_vector kernel, 5f + + movi a2, 0x0400000c /* PPN */ + movi a3, 0x00008000 /* VPN */ + wdtlb a2, a3 + movi a2, 0x00007ffd + movi a3, 0x00008000 + /* DTLB: FAIL, ITLB: FAIL */ + jx a2 +5: + rsr a2, exccause + movi a3, 28 + assert eq, a2, a3 + rsr a2, epc1 + movi a3, 0x7ffd + assert eq, a2, a3 + rsr a2, excsave1 + movi a3, 0x00007ffd + assert eq, a2, a3 +test_end + test_suite_end diff --git a/tests/test-aio.c b/tests/test-aio.c index e5f8b55d3..f12b6e0ae 100644 --- a/tests/test-aio.c +++ b/tests/test-aio.c @@ -15,7 +15,7 @@ #include "qemu/timer.h" #include "qemu/sockets.h" -AioContext *ctx; +static AioContext *ctx; typedef struct { EventNotifier e; @@ -24,14 +24,6 @@ typedef struct { bool auto_set; } EventNotifierTestData; -/* Wait until there are no more BHs or AIO requests */ -static void wait_for_aio(void) -{ - while (aio_poll(ctx, true)) { - /* Do nothing */ - } -} - /* Wait until event notifier becomes inactive */ static void wait_until_inactive(EventNotifierTestData *data) { @@ -204,7 +196,9 @@ static void test_bh_schedule10(void) g_assert(aio_poll(ctx, true)); g_assert_cmpint(data.n, ==, 2); - wait_for_aio(); + while (data.n < 10) { + aio_poll(ctx, true); + } g_assert_cmpint(data.n, ==, 10); g_assert(!aio_poll(ctx, false)); @@ -252,7 +246,9 @@ static void test_bh_delete_from_cb(void) qemu_bh_schedule(data1.bh); g_assert_cmpint(data1.n, ==, 0); - wait_for_aio(); + while (data1.n < data1.max) { + aio_poll(ctx, true); + } g_assert_cmpint(data1.n, ==, data1.max); g_assert(data1.bh == NULL); @@ -287,7 +283,12 @@ static void test_bh_delete_from_cb_many(void) g_assert_cmpint(data4.n, ==, 1); g_assert(data1.bh == NULL); - wait_for_aio(); + while (data1.n < data1.max || + data2.n < data2.max || + data3.n < data3.max || + data4.n < data4.max) { + aio_poll(ctx, true); + } g_assert_cmpint(data1.n, ==, data1.max); g_assert_cmpint(data2.n, ==, data2.max); g_assert_cmpint(data3.n, ==, data3.max); @@ -306,7 +307,7 @@ static void test_bh_flush(void) qemu_bh_schedule(data.bh); g_assert_cmpint(data.n, ==, 0); - wait_for_aio(); + g_assert(aio_poll(ctx, true)); g_assert_cmpint(data.n, ==, 1); g_assert(!aio_poll(ctx, false)); @@ -806,17 +807,16 @@ static void test_source_timer_schedule(void) g_usleep(1 * G_USEC_PER_SEC); g_assert_cmpint(data.n, ==, 0); - g_assert(g_main_context_iteration(NULL, false)); + g_assert(g_main_context_iteration(NULL, true)); g_assert_cmpint(data.n, ==, 1); + expiry += data.ns; - /* The comment above was not kidding when it said this wakes up itself */ - do { - g_assert(g_main_context_iteration(NULL, true)); - } while (qemu_clock_get_ns(data.clock_type) <= expiry); - g_usleep(1 * G_USEC_PER_SEC); - g_main_context_iteration(NULL, false); + while (data.n < 2) { + g_main_context_iteration(NULL, true); + } g_assert_cmpint(data.n, ==, 2); + g_assert(qemu_clock_get_ns(data.clock_type) > expiry); aio_set_fd_handler(ctx, pipefd[0], NULL, NULL, NULL); close(pipefd[0]); diff --git a/tests/test-qdev-global-props.c b/tests/test-qdev-global-props.c index e4ad173d7..2bef04c76 100644 --- a/tests/test-qdev-global-props.c +++ b/tests/test-qdev-global-props.c @@ -150,8 +150,10 @@ static void test_dynamic_globalprop(void) static GlobalProperty props[] = { { TYPE_DYNAMIC_PROPS, "prop1", "101" }, { TYPE_DYNAMIC_PROPS, "prop2", "102" }, + { TYPE_DYNAMIC_PROPS"-bad", "prop3", "103", true }, {} }; + int all_used; qdev_prop_register_global_list(props); @@ -160,6 +162,8 @@ static void test_dynamic_globalprop(void) g_assert_cmpuint(mt->prop1, ==, 101); g_assert_cmpuint(mt->prop2, ==, 102); + all_used = qdev_prop_check_global(); + g_assert_cmpuint(all_used, ==, 1); } int main(int argc, char **argv) diff --git a/tests/test-qemu-opts.c b/tests/test-qemu-opts.c new file mode 100644 index 000000000..ca08ac523 --- /dev/null +++ b/tests/test-qemu-opts.c @@ -0,0 +1,441 @@ +/* + * QemuOpts unit-tests. + * + * Copyright (C) 2014 Leandro Dorileo <l@dorileo.org> + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + */ + +#include "qapi/error.h" +#include "qapi/qmp/qstring.h" +#include "qemu/config-file.h" + +#include <glib.h> +#include <string.h> + +static QemuOptsList opts_list_01 = { + .name = "opts_list_01", + .head = QTAILQ_HEAD_INITIALIZER(opts_list_01.head), + .desc = { + { + .name = "str1", + .type = QEMU_OPT_STRING, + },{ + .name = "str2", + .type = QEMU_OPT_STRING, + },{ + .name = "str3", + .type = QEMU_OPT_STRING, + },{ + .name = "number1", + .type = QEMU_OPT_NUMBER, + }, + { /* end of list */ } + }, +}; + +static QemuOptsList opts_list_02 = { + .name = "opts_list_02", + .head = QTAILQ_HEAD_INITIALIZER(opts_list_02.head), + .desc = { + { + .name = "str1", + .type = QEMU_OPT_STRING, + },{ + .name = "bool1", + .type = QEMU_OPT_BOOL, + },{ + .name = "str2", + .type = QEMU_OPT_STRING, + },{ + .name = "size1", + .type = QEMU_OPT_SIZE, + }, + { /* end of list */ } + }, +}; + +static QemuOptsList opts_list_03 = { + .name = "opts_list_03", + .head = QTAILQ_HEAD_INITIALIZER(opts_list_03.head), + .desc = { + /* no elements => accept any params */ + { /* end of list */ } + }, +}; + +static void register_opts(void) +{ + qemu_add_opts(&opts_list_01); + qemu_add_opts(&opts_list_02); + qemu_add_opts(&opts_list_03); +} + +static void test_find_unknown_opts(void) +{ + QemuOptsList *list; + Error *err = NULL; + + /* should not return anything, we don't have an "unknown" option */ + list = qemu_find_opts_err("unknown", &err); + g_assert(list == NULL); + g_assert(err); + error_free(err); +} + +static void test_qemu_find_opts(void) +{ + QemuOptsList *list; + + /* we have an "opts_list_01" option, should return it */ + list = qemu_find_opts("opts_list_01"); + g_assert(list != NULL); + g_assert_cmpstr(list->name, ==, "opts_list_01"); +} + +static void test_qemu_opts_create(void) +{ + QemuOptsList *list; + QemuOpts *opts; + + list = qemu_find_opts("opts_list_01"); + g_assert(list != NULL); + g_assert(QTAILQ_EMPTY(&list->head)); + g_assert_cmpstr(list->name, ==, "opts_list_01"); + + /* should not find anything at this point */ + opts = qemu_opts_find(list, NULL); + g_assert(opts == NULL); + + /* create the opts */ + opts = qemu_opts_create(list, NULL, 0, &error_abort); + g_assert(opts != NULL); + g_assert(!QTAILQ_EMPTY(&list->head)); + + /* now we've create the opts, must find it */ + opts = qemu_opts_find(list, NULL); + g_assert(opts != NULL); + + qemu_opts_del(opts); + + /* should not find anything at this point */ + opts = qemu_opts_find(list, NULL); + g_assert(opts == NULL); +} + +static void test_qemu_opt_get(void) +{ + QemuOptsList *list; + QemuOpts *opts; + const char *opt = NULL; + + list = qemu_find_opts("opts_list_01"); + g_assert(list != NULL); + g_assert(QTAILQ_EMPTY(&list->head)); + g_assert_cmpstr(list->name, ==, "opts_list_01"); + + /* should not find anything at this point */ + opts = qemu_opts_find(list, NULL); + g_assert(opts == NULL); + + /* create the opts */ + opts = qemu_opts_create(list, NULL, 0, &error_abort); + g_assert(opts != NULL); + g_assert(!QTAILQ_EMPTY(&list->head)); + + /* haven't set anything to str2 yet */ + opt = qemu_opt_get(opts, "str2"); + g_assert(opt == NULL); + + qemu_opt_set(opts, "str2", "value"); + + /* now we have set str2, should know about it */ + opt = qemu_opt_get(opts, "str2"); + g_assert_cmpstr(opt, ==, "value"); + + qemu_opt_set(opts, "str2", "value2"); + + /* having reset the value, the returned should be the reset one */ + opt = qemu_opt_get(opts, "str2"); + g_assert_cmpstr(opt, ==, "value2"); + + qemu_opts_del(opts); + + /* should not find anything at this point */ + opts = qemu_opts_find(list, NULL); + g_assert(opts == NULL); +} + +static void test_qemu_opt_get_bool(void) +{ + QemuOptsList *list; + QemuOpts *opts; + bool opt; + int ret; + + list = qemu_find_opts("opts_list_02"); + g_assert(list != NULL); + g_assert(QTAILQ_EMPTY(&list->head)); + g_assert_cmpstr(list->name, ==, "opts_list_02"); + + /* should not find anything at this point */ + opts = qemu_opts_find(list, NULL); + g_assert(opts == NULL); + + /* create the opts */ + opts = qemu_opts_create(list, NULL, 0, &error_abort); + g_assert(opts != NULL); + g_assert(!QTAILQ_EMPTY(&list->head)); + + /* haven't set anything to bool1 yet, so defval should be returned */ + opt = qemu_opt_get_bool(opts, "bool1", false); + g_assert(opt == false); + + ret = qemu_opt_set_bool(opts, "bool1", true); + g_assert(ret == 0); + + /* now we have set bool1, should know about it */ + opt = qemu_opt_get_bool(opts, "bool1", false); + g_assert(opt == true); + + /* having reset the value, opt should be the reset one not defval */ + ret = qemu_opt_set_bool(opts, "bool1", false); + g_assert(ret == 0); + + opt = qemu_opt_get_bool(opts, "bool1", true); + g_assert(opt == false); + + qemu_opts_del(opts); + + /* should not find anything at this point */ + opts = qemu_opts_find(list, NULL); + g_assert(opts == NULL); +} + +static void test_qemu_opt_get_number(void) +{ + QemuOptsList *list; + QemuOpts *opts; + uint64_t opt; + int ret; + + list = qemu_find_opts("opts_list_01"); + g_assert(list != NULL); + g_assert(QTAILQ_EMPTY(&list->head)); + g_assert_cmpstr(list->name, ==, "opts_list_01"); + + /* should not find anything at this point */ + opts = qemu_opts_find(list, NULL); + g_assert(opts == NULL); + + /* create the opts */ + opts = qemu_opts_create(list, NULL, 0, &error_abort); + g_assert(opts != NULL); + g_assert(!QTAILQ_EMPTY(&list->head)); + + /* haven't set anything to number1 yet, so defval should be returned */ + opt = qemu_opt_get_number(opts, "number1", 5); + g_assert(opt == 5); + + ret = qemu_opt_set_number(opts, "number1", 10); + g_assert(ret == 0); + + /* now we have set number1, should know about it */ + opt = qemu_opt_get_number(opts, "number1", 5); + g_assert(opt == 10); + + /* having reset it, the returned should be the reset one not defval */ + ret = qemu_opt_set_number(opts, "number1", 15); + g_assert(ret == 0); + + opt = qemu_opt_get_number(opts, "number1", 5); + g_assert(opt == 15); + + qemu_opts_del(opts); + + /* should not find anything at this point */ + opts = qemu_opts_find(list, NULL); + g_assert(opts == NULL); +} + +static void test_qemu_opt_get_size(void) +{ + QemuOptsList *list; + QemuOpts *opts; + uint64_t opt; + QDict *dict; + + list = qemu_find_opts("opts_list_02"); + g_assert(list != NULL); + g_assert(QTAILQ_EMPTY(&list->head)); + g_assert_cmpstr(list->name, ==, "opts_list_02"); + + /* should not find anything at this point */ + opts = qemu_opts_find(list, NULL); + g_assert(opts == NULL); + + /* create the opts */ + opts = qemu_opts_create(list, NULL, 0, &error_abort); + g_assert(opts != NULL); + g_assert(!QTAILQ_EMPTY(&list->head)); + + /* haven't set anything to size1 yet, so defval should be returned */ + opt = qemu_opt_get_size(opts, "size1", 5); + g_assert(opt == 5); + + dict = qdict_new(); + g_assert(dict != NULL); + + qdict_put(dict, "size1", qstring_from_str("10")); + + qemu_opts_absorb_qdict(opts, dict, &error_abort); + g_assert(error_abort == NULL); + + /* now we have set size1, should know about it */ + opt = qemu_opt_get_size(opts, "size1", 5); + g_assert(opt == 10); + + /* reset value */ + qdict_put(dict, "size1", qstring_from_str("15")); + + qemu_opts_absorb_qdict(opts, dict, &error_abort); + g_assert(error_abort == NULL); + + /* test the reset value */ + opt = qemu_opt_get_size(opts, "size1", 5); + g_assert(opt == 15); + + qdict_del(dict, "size1"); + g_free(dict); + + qemu_opts_del(opts); + + /* should not find anything at this point */ + opts = qemu_opts_find(list, NULL); + g_assert(opts == NULL); +} + +static void test_qemu_opt_unset(void) +{ + QemuOpts *opts; + const char *value; + int ret; + + /* dynamically initialized (parsed) opts */ + opts = qemu_opts_parse(&opts_list_03, "key=value", 0); + g_assert(opts != NULL); + + /* check default/parsed value */ + value = qemu_opt_get(opts, "key"); + g_assert_cmpstr(value, ==, "value"); + + /* reset it to value2 */ + qemu_opt_set(opts, "key", "value2"); + + value = qemu_opt_get(opts, "key"); + g_assert_cmpstr(value, ==, "value2"); + + /* unset, valid only for "accept any" */ + ret = qemu_opt_unset(opts, "key"); + g_assert(ret == 0); + + /* after reset the value should be the parsed/default one */ + value = qemu_opt_get(opts, "key"); + g_assert_cmpstr(value, ==, "value"); + + qemu_opts_del(opts); +} + +static void test_qemu_opts_reset(void) +{ + QemuOptsList *list; + QemuOpts *opts; + uint64_t opt; + int ret; + + list = qemu_find_opts("opts_list_01"); + g_assert(list != NULL); + g_assert(QTAILQ_EMPTY(&list->head)); + g_assert_cmpstr(list->name, ==, "opts_list_01"); + + /* should not find anything at this point */ + opts = qemu_opts_find(list, NULL); + g_assert(opts == NULL); + + /* create the opts */ + opts = qemu_opts_create(list, NULL, 0, &error_abort); + g_assert(opts != NULL); + g_assert(!QTAILQ_EMPTY(&list->head)); + + /* haven't set anything to number1 yet, so defval should be returned */ + opt = qemu_opt_get_number(opts, "number1", 5); + g_assert(opt == 5); + + ret = qemu_opt_set_number(opts, "number1", 10); + g_assert(ret == 0); + + /* now we have set number1, should know about it */ + opt = qemu_opt_get_number(opts, "number1", 5); + g_assert(opt == 10); + + qemu_opts_reset(list); + + /* should not find anything at this point */ + opts = qemu_opts_find(list, NULL); + g_assert(opts == NULL); +} + +static void test_qemu_opts_set(void) +{ + QemuOptsList *list; + QemuOpts *opts; + int ret; + const char *opt; + + list = qemu_find_opts("opts_list_01"); + g_assert(list != NULL); + g_assert(QTAILQ_EMPTY(&list->head)); + g_assert_cmpstr(list->name, ==, "opts_list_01"); + + /* should not find anything at this point */ + opts = qemu_opts_find(list, NULL); + g_assert(opts == NULL); + + /* implicitly create opts and set str3 value */ + ret = qemu_opts_set(list, NULL, "str3", "value"); + g_assert(ret == 0); + g_assert(!QTAILQ_EMPTY(&list->head)); + + /* get the just created opts */ + opts = qemu_opts_find(list, NULL); + g_assert(opts != NULL); + + /* check the str3 value */ + opt = qemu_opt_get(opts, "str3"); + g_assert_cmpstr(opt, ==, "value"); + + qemu_opts_del(opts); + + /* should not find anything at this point */ + opts = qemu_opts_find(list, NULL); + g_assert(opts == NULL); +} + +int main(int argc, char *argv[]) +{ + register_opts(); + g_test_init(&argc, &argv, NULL); + g_test_add_func("/qemu-opts/find_unknown_opts", test_find_unknown_opts); + g_test_add_func("/qemu-opts/find_opts", test_qemu_find_opts); + g_test_add_func("/qemu-opts/opts_create", test_qemu_opts_create); + g_test_add_func("/qemu-opts/opt_get", test_qemu_opt_get); + g_test_add_func("/qemu-opts/opt_get_bool", test_qemu_opt_get_bool); + g_test_add_func("/qemu-opts/opt_get_number", test_qemu_opt_get_number); + g_test_add_func("/qemu-opts/opt_get_size", test_qemu_opt_get_size); + g_test_add_func("/qemu-opts/opt_unset", test_qemu_opt_unset); + g_test_add_func("/qemu-opts/opts_reset", test_qemu_opts_reset); + g_test_add_func("/qemu-opts/opts_set", test_qemu_opts_set); + g_test_run(); + return 0; +} diff --git a/tests/test-qmp-event.c b/tests/test-qmp-event.c new file mode 100644 index 000000000..cb354e6e8 --- /dev/null +++ b/tests/test-qmp-event.c @@ -0,0 +1,271 @@ +/* + * qapi event unit-tests. + * + * Copyright (c) 2014 Wenchao Xia + * + * Authors: + * Wenchao Xia <wenchaoqemu@gmail.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#include <glib.h> +#include <stdarg.h> + +#include "qemu-common.h" +#include "test-qapi-types.h" +#include "test-qapi-visit.h" +#include "test-qapi-event.h" +#include "qapi/qmp/types.h" +#include "qapi/qmp/qint.h" +#include "qapi/qmp/qobject.h" +#include "qapi/qmp-event.h" + +typedef struct TestEventData { + QDict *expect; +} TestEventData; + +typedef struct QDictCmpData { + QDict *expect; + bool result; +} QDictCmpData; + +TestEventData *test_event_data; +static CompatGMutex test_event_lock; + +/* Only compares bool, int, string */ +static +void qdict_cmp_do_simple(const char *key, QObject *obj1, void *opaque) + +{ + QObject *obj2; + QDictCmpData d_new, *d = opaque; + + if (!d->result) { + return; + } + + obj2 = qdict_get(d->expect, key); + if (!obj2) { + d->result = false; + return; + } + + if (qobject_type(obj1) != qobject_type(obj2)) { + d->result = false; + return; + } + + switch (qobject_type(obj1)) { + case QTYPE_QBOOL: + d->result = (qbool_get_int(qobject_to_qbool(obj1)) == + qbool_get_int(qobject_to_qbool(obj2))); + return; + case QTYPE_QINT: + d->result = (qint_get_int(qobject_to_qint(obj1)) == + qint_get_int(qobject_to_qint(obj2))); + return; + case QTYPE_QSTRING: + d->result = g_strcmp0(qstring_get_str(qobject_to_qstring(obj1)), + qstring_get_str(qobject_to_qstring(obj2))) == 0; + return; + case QTYPE_QDICT: + d_new.expect = qobject_to_qdict(obj2); + d_new.result = true; + qdict_iter(qobject_to_qdict(obj1), qdict_cmp_do_simple, &d_new); + d->result = d_new.result; + return; + default: + abort(); + } +} + +static bool qdict_cmp_simple(QDict *a, QDict *b) +{ + QDictCmpData d; + + d.expect = b; + d.result = true; + qdict_iter(a, qdict_cmp_do_simple, &d); + return d.result; +} + +/* This function is hooked as final emit function, which can verify the + correctness. */ +static void event_test_emit(TEST_QAPIEvent event, QDict *d, Error **errp) +{ + QObject *obj; + QDict *t; + int64_t s, ms; + + /* Verify that we have timestamp, then remove it to compare other fields */ + obj = qdict_get(d, "timestamp"); + g_assert(obj); + t = qobject_to_qdict(obj); + g_assert(t); + obj = qdict_get(t, "seconds"); + g_assert(obj && qobject_type(obj) == QTYPE_QINT); + s = qint_get_int(qobject_to_qint(obj)); + obj = qdict_get(t, "microseconds"); + g_assert(obj && qobject_type(obj) == QTYPE_QINT); + ms = qint_get_int(qobject_to_qint(obj)); + if (s == -1) { + g_assert(ms == -1); + } else { + g_assert(ms >= 0 && ms <= 999999); + } + g_assert(qdict_size(t) == 2); + + qdict_del(d, "timestamp"); + + g_assert(qdict_cmp_simple(d, test_event_data->expect)); + +} + +static void event_prepare(TestEventData *data, + const void *unused) +{ + /* Global variable test_event_data was used to pass the expectation, so + test cases can't be executed at same time. */ + g_mutex_lock(&test_event_lock); + + data->expect = qdict_new(); + test_event_data = data; +} + +static void event_teardown(TestEventData *data, + const void *unused) +{ + QDECREF(data->expect); + test_event_data = NULL; + + g_mutex_unlock(&test_event_lock); +} + +static void event_test_add(const char *testpath, + void (*test_func)(TestEventData *data, + const void *user_data)) +{ + g_test_add(testpath, TestEventData, NULL, event_prepare, test_func, + event_teardown); +} + + +/* Test cases */ + +static void test_event_a(TestEventData *data, + const void *unused) +{ + QDict *d; + d = data->expect; + qdict_put(d, "event", qstring_from_str("EVENT_A")); + qapi_event_send_event_a(&error_abort); +} + +static void test_event_b(TestEventData *data, + const void *unused) +{ + QDict *d; + d = data->expect; + qdict_put(d, "event", qstring_from_str("EVENT_B")); + qapi_event_send_event_b(&error_abort); +} + +static void test_event_c(TestEventData *data, + const void *unused) +{ + QDict *d, *d_data, *d_b; + + UserDefOne b; + UserDefZero z; + z.integer = 2; + b.base = &z; + b.string = g_strdup("test1"); + b.has_enum1 = false; + + d_b = qdict_new(); + qdict_put(d_b, "integer", qint_from_int(2)); + qdict_put(d_b, "string", qstring_from_str("test1")); + + d_data = qdict_new(); + qdict_put(d_data, "a", qint_from_int(1)); + qdict_put(d_data, "b", d_b); + qdict_put(d_data, "c", qstring_from_str("test2")); + + d = data->expect; + qdict_put(d, "event", qstring_from_str("EVENT_C")); + qdict_put(d, "data", d_data); + + qapi_event_send_event_c(true, 1, true, &b, "test2", &error_abort); + + g_free(b.string); +} + +/* Complex type */ +static void test_event_d(TestEventData *data, + const void *unused) +{ + UserDefOne struct1; + EventStructOne a; + UserDefZero z; + QDict *d, *d_data, *d_a, *d_struct1; + + z.integer = 2; + struct1.base = &z; + struct1.string = g_strdup("test1"); + struct1.has_enum1 = true; + struct1.enum1 = ENUM_ONE_VALUE1; + + a.struct1 = &struct1; + a.string = g_strdup("test2"); + a.has_enum2 = true; + a.enum2 = ENUM_ONE_VALUE2; + + d_struct1 = qdict_new(); + qdict_put(d_struct1, "integer", qint_from_int(2)); + qdict_put(d_struct1, "string", qstring_from_str("test1")); + qdict_put(d_struct1, "enum1", qstring_from_str("value1")); + + d_a = qdict_new(); + qdict_put(d_a, "struct1", d_struct1); + qdict_put(d_a, "string", qstring_from_str("test2")); + qdict_put(d_a, "enum2", qstring_from_str("value2")); + + d_data = qdict_new(); + qdict_put(d_data, "a", d_a); + qdict_put(d_data, "b", qstring_from_str("test3")); + qdict_put(d_data, "enum3", qstring_from_str("value3")); + + d = data->expect; + qdict_put(d, "event", qstring_from_str("EVENT_D")); + qdict_put(d, "data", d_data); + + qapi_event_send_event_d(&a, "test3", false, NULL, true, ENUM_ONE_VALUE3, + &error_abort); + + g_free(struct1.string); + g_free(a.string); +} + +int main(int argc, char **argv) +{ +#if !GLIB_CHECK_VERSION(2, 31, 0) + if (!g_thread_supported()) { + g_thread_init(NULL); + } +#endif + + qmp_event_set_func_emit(event_test_emit); + + g_test_init(&argc, &argv, NULL); + + event_test_add("/event/event_a", test_event_a); + event_test_add("/event/event_b", test_event_b); + event_test_add("/event/event_c", test_event_c); + event_test_add("/event/event_d", test_event_d); + g_test_run(); + + return 0; +} diff --git a/tests/test-qmp-input-strict.c b/tests/test-qmp-input-strict.c index 38b5e95f6..0f770034b 100644 --- a/tests/test-qmp-input-strict.c +++ b/tests/test-qmp-input-strict.c @@ -72,27 +72,43 @@ typedef struct TestStruct static void visit_type_TestStruct(Visitor *v, TestStruct **obj, const char *name, Error **errp) { - visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct), - errp); + Error *err = NULL; - visit_type_int(v, &(*obj)->integer, "integer", errp); - visit_type_bool(v, &(*obj)->boolean, "boolean", errp); - visit_type_str(v, &(*obj)->string, "string", errp); + visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct), + &err); + if (err) { + goto out; + } - visit_end_struct(v, errp); + visit_type_int(v, &(*obj)->integer, "integer", &err); + if (err) { + goto out_end; + } + visit_type_bool(v, &(*obj)->boolean, "boolean", &err); + if (err) { + goto out_end; + } + visit_type_str(v, &(*obj)->string, "string", &err); + +out_end: + error_propagate(errp, err); + err = NULL; + visit_end_struct(v, &err); +out: + error_propagate(errp, err); } static void test_validate_struct(TestInputVisitorData *data, const void *unused) { TestStruct *p = NULL; - Error *errp = NULL; + Error *err = NULL; Visitor *v; v = validate_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo' }"); - visit_type_TestStruct(v, &p, NULL, &errp); - g_assert(!errp); + visit_type_TestStruct(v, &p, NULL, &err); + g_assert(!err); g_free(p->string); g_free(p); } @@ -101,13 +117,13 @@ static void test_validate_struct_nested(TestInputVisitorData *data, const void *unused) { UserDefNested *udp = NULL; - Error *errp = NULL; + Error *err = NULL; Visitor *v; v = validate_test_init(data, "{ 'string0': 'string0', 'dict1': { 'string1': 'string1', 'dict2': { 'userdef1': { 'integer': 42, 'string': 'string' }, 'string2': 'string2'}}}"); - visit_type_UserDefNested(v, &udp, NULL, &errp); - g_assert(!errp); + visit_type_UserDefNested(v, &udp, NULL, &err); + g_assert(!err); qapi_free_UserDefNested(udp); } @@ -115,13 +131,13 @@ static void test_validate_list(TestInputVisitorData *data, const void *unused) { UserDefOneList *head = NULL; - Error *errp = NULL; + Error *err = NULL; Visitor *v; v = validate_test_init(data, "[ { 'string': 'string0', 'integer': 42 }, { 'string': 'string1', 'integer': 43 }, { 'string': 'string2', 'integer': 44 } ]"); - visit_type_UserDefOneList(v, &head, NULL, &errp); - g_assert(!errp); + visit_type_UserDefOneList(v, &head, NULL, &err); + g_assert(!err); qapi_free_UserDefOneList(head); } @@ -130,12 +146,12 @@ static void test_validate_union(TestInputVisitorData *data, { UserDefUnion *tmp = NULL; Visitor *v; - Error *errp = NULL; + Error *err = NULL; v = validate_test_init(data, "{ 'type': 'b', 'integer': 41, 'data' : { 'integer': 42 } }"); - visit_type_UserDefUnion(v, &tmp, NULL, &errp); - g_assert(!errp); + visit_type_UserDefUnion(v, &tmp, NULL, &err); + g_assert(!err); qapi_free_UserDefUnion(tmp); } @@ -144,7 +160,7 @@ static void test_validate_union_flat(TestInputVisitorData *data, { UserDefFlatUnion *tmp = NULL; Visitor *v; - Error *errp = NULL; + Error *err = NULL; v = validate_test_init(data, "{ 'enum1': 'value1', " @@ -152,8 +168,8 @@ static void test_validate_union_flat(TestInputVisitorData *data, "'boolean': true }"); /* TODO when generator bug is fixed, add 'integer': 41 */ - visit_type_UserDefFlatUnion(v, &tmp, NULL, &errp); - g_assert(!error_is_set(&errp)); + visit_type_UserDefFlatUnion(v, &tmp, NULL, &err); + g_assert(!err); qapi_free_UserDefFlatUnion(tmp); } @@ -162,12 +178,12 @@ static void test_validate_union_anon(TestInputVisitorData *data, { UserDefAnonUnion *tmp = NULL; Visitor *v; - Error *errp = NULL; + Error *err = NULL; v = validate_test_init(data, "42"); - visit_type_UserDefAnonUnion(v, &tmp, NULL, &errp); - g_assert(!error_is_set(&errp)); + visit_type_UserDefAnonUnion(v, &tmp, NULL, &err); + g_assert(!err); qapi_free_UserDefAnonUnion(tmp); } @@ -175,13 +191,13 @@ static void test_validate_fail_struct(TestInputVisitorData *data, const void *unused) { TestStruct *p = NULL; - Error *errp = NULL; + Error *err = NULL; Visitor *v; v = validate_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo', 'extra': 42 }"); - visit_type_TestStruct(v, &p, NULL, &errp); - g_assert(errp); + visit_type_TestStruct(v, &p, NULL, &err); + g_assert(err); if (p) { g_free(p->string); } @@ -192,13 +208,13 @@ static void test_validate_fail_struct_nested(TestInputVisitorData *data, const void *unused) { UserDefNested *udp = NULL; - Error *errp = NULL; + Error *err = NULL; Visitor *v; v = validate_test_init(data, "{ 'string0': 'string0', 'dict1': { 'string1': 'string1', 'dict2': { 'userdef1': { 'integer': 42, 'string': 'string', 'extra': [42, 23, {'foo':'bar'}] }, 'string2': 'string2'}}}"); - visit_type_UserDefNested(v, &udp, NULL, &errp); - g_assert(errp); + visit_type_UserDefNested(v, &udp, NULL, &err); + g_assert(err); qapi_free_UserDefNested(udp); } @@ -206,13 +222,13 @@ static void test_validate_fail_list(TestInputVisitorData *data, const void *unused) { UserDefOneList *head = NULL; - Error *errp = NULL; + Error *err = NULL; Visitor *v; v = validate_test_init(data, "[ { 'string': 'string0', 'integer': 42 }, { 'string': 'string1', 'integer': 43 }, { 'string': 'string2', 'integer': 44, 'extra': 'ggg' } ]"); - visit_type_UserDefOneList(v, &head, NULL, &errp); - g_assert(errp); + visit_type_UserDefOneList(v, &head, NULL, &err); + g_assert(err); qapi_free_UserDefOneList(head); } @@ -220,13 +236,13 @@ static void test_validate_fail_union(TestInputVisitorData *data, const void *unused) { UserDefUnion *tmp = NULL; - Error *errp = NULL; + Error *err = NULL; Visitor *v; v = validate_test_init(data, "{ 'type': 'b', 'data' : { 'integer': 42 } }"); - visit_type_UserDefUnion(v, &tmp, NULL, &errp); - g_assert(errp); + visit_type_UserDefUnion(v, &tmp, NULL, &err); + g_assert(err); qapi_free_UserDefUnion(tmp); } @@ -234,13 +250,13 @@ static void test_validate_fail_union_flat(TestInputVisitorData *data, const void *unused) { UserDefFlatUnion *tmp = NULL; - Error *errp = NULL; + Error *err = NULL; Visitor *v; v = validate_test_init(data, "{ 'string': 'c', 'integer': 41, 'boolean': true }"); - visit_type_UserDefFlatUnion(v, &tmp, NULL, &errp); - g_assert(error_is_set(&errp)); + visit_type_UserDefFlatUnion(v, &tmp, NULL, &err); + g_assert(err); qapi_free_UserDefFlatUnion(tmp); } @@ -249,12 +265,12 @@ static void test_validate_fail_union_anon(TestInputVisitorData *data, { UserDefAnonUnion *tmp = NULL; Visitor *v; - Error *errp = NULL; + Error *err = NULL; v = validate_test_init(data, "3.14"); - visit_type_UserDefAnonUnion(v, &tmp, NULL, &errp); - g_assert(error_is_set(&errp)); + visit_type_UserDefAnonUnion(v, &tmp, NULL, &err); + g_assert(err); qapi_free_UserDefAnonUnion(tmp); } diff --git a/tests/test-qmp-input-visitor.c b/tests/test-qmp-input-visitor.c index 1729667a6..1c8e87295 100644 --- a/tests/test-qmp-input-visitor.c +++ b/tests/test-qmp-input-visitor.c @@ -90,13 +90,13 @@ static void test_visitor_in_int(TestInputVisitorData *data, const void *unused) { int64_t res = 0, value = -42; - Error *errp = NULL; + Error *err = NULL; Visitor *v; v = visitor_input_test_init(data, "%" PRId64, value); - visit_type_int(v, &res, NULL, &errp); - g_assert(!errp); + visit_type_int(v, &res, NULL, &err); + g_assert(!err); g_assert_cmpint(res, ==, value); } @@ -104,7 +104,7 @@ static void test_visitor_in_int_overflow(TestInputVisitorData *data, const void *unused) { int64_t res = 0; - Error *errp = NULL; + Error *err = NULL; Visitor *v; /* this will overflow a Qint/int64, so should be deserialized into @@ -113,22 +113,22 @@ static void test_visitor_in_int_overflow(TestInputVisitorData *data, */ v = visitor_input_test_init(data, "%f", DBL_MAX); - visit_type_int(v, &res, NULL, &errp); - g_assert(errp); - error_free(errp); + visit_type_int(v, &res, NULL, &err); + g_assert(err); + error_free(err); } static void test_visitor_in_bool(TestInputVisitorData *data, const void *unused) { - Error *errp = NULL; + Error *err = NULL; bool res = false; Visitor *v; v = visitor_input_test_init(data, "true"); - visit_type_bool(v, &res, NULL, &errp); - g_assert(!errp); + visit_type_bool(v, &res, NULL, &err); + g_assert(!err); g_assert_cmpint(res, ==, true); } @@ -136,13 +136,13 @@ static void test_visitor_in_number(TestInputVisitorData *data, const void *unused) { double res = 0, value = 3.14; - Error *errp = NULL; + Error *err = NULL; Visitor *v; v = visitor_input_test_init(data, "%f", value); - visit_type_number(v, &res, NULL, &errp); - g_assert(!errp); + visit_type_number(v, &res, NULL, &err); + g_assert(!err); g_assert_cmpfloat(res, ==, value); } @@ -150,13 +150,13 @@ static void test_visitor_in_string(TestInputVisitorData *data, const void *unused) { char *res = NULL, *value = (char *) "Q E M U"; - Error *errp = NULL; + Error *err = NULL; Visitor *v; v = visitor_input_test_init(data, "%s", value); - visit_type_str(v, &res, NULL, &errp); - g_assert(!errp); + visit_type_str(v, &res, NULL, &err); + g_assert(!err); g_assert_cmpstr(res, ==, value); g_free(res); @@ -165,7 +165,7 @@ static void test_visitor_in_string(TestInputVisitorData *data, static void test_visitor_in_enum(TestInputVisitorData *data, const void *unused) { - Error *errp = NULL; + Error *err = NULL; Visitor *v; EnumOne i; @@ -174,8 +174,8 @@ static void test_visitor_in_enum(TestInputVisitorData *data, v = visitor_input_test_init(data, "%s", EnumOne_lookup[i]); - visit_type_EnumOne(v, &res, NULL, &errp); - g_assert(!errp); + visit_type_EnumOne(v, &res, NULL, &err); + g_assert(!err); g_assert_cmpint(i, ==, res); visitor_input_teardown(data, NULL); @@ -196,34 +196,41 @@ static void visit_type_TestStruct(Visitor *v, TestStruct **obj, const char *name, Error **errp) { Error *err = NULL; - if (!error_is_set(errp)) { - visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct), - &err); - if (!err) { - visit_type_int(v, &(*obj)->integer, "integer", &err); - visit_type_bool(v, &(*obj)->boolean, "boolean", &err); - visit_type_str(v, &(*obj)->string, "string", &err); - - /* Always call end_struct if start_struct succeeded. */ - error_propagate(errp, err); - err = NULL; - visit_end_struct(v, &err); - } - error_propagate(errp, err); + + visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct), + &err); + if (err) { + goto out; } + visit_type_int(v, &(*obj)->integer, "integer", &err); + if (err) { + goto out_end; + } + visit_type_bool(v, &(*obj)->boolean, "boolean", &err); + if (err) { + goto out_end; + } + visit_type_str(v, &(*obj)->string, "string", &err); + +out_end: + error_propagate(errp, err); + err = NULL; + visit_end_struct(v, &err); +out: + error_propagate(errp, err); } static void test_visitor_in_struct(TestInputVisitorData *data, const void *unused) { TestStruct *p = NULL; - Error *errp = NULL; + Error *err = NULL; Visitor *v; v = visitor_input_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo' }"); - visit_type_TestStruct(v, &p, NULL, &errp); - g_assert(!errp); + visit_type_TestStruct(v, &p, NULL, &err); + g_assert(!err); g_assert_cmpint(p->integer, ==, -42); g_assert(p->boolean == true); g_assert_cmpstr(p->string, ==, "foo"); @@ -242,13 +249,13 @@ static void test_visitor_in_struct_nested(TestInputVisitorData *data, const void *unused) { UserDefNested *udp = NULL; - Error *errp = NULL; + Error *err = NULL; Visitor *v; v = visitor_input_test_init(data, "{ 'string0': 'string0', 'dict1': { 'string1': 'string1', 'dict2': { 'userdef1': { 'integer': 42, 'string': 'string' }, 'string2': 'string2'}}}"); - visit_type_UserDefNested(v, &udp, NULL, &errp); - g_assert(!errp); + visit_type_UserDefNested(v, &udp, NULL, &err); + g_assert(!err); check_and_free_str(udp->string0, "string0"); check_and_free_str(udp->dict1.string1, "string1"); @@ -265,14 +272,14 @@ static void test_visitor_in_list(TestInputVisitorData *data, const void *unused) { UserDefOneList *item, *head = NULL; - Error *errp = NULL; + Error *err = NULL; Visitor *v; int i; v = visitor_input_test_init(data, "[ { 'string': 'string0', 'integer': 42 }, { 'string': 'string1', 'integer': 43 }, { 'string': 'string2', 'integer': 44 } ]"); - visit_type_UserDefOneList(v, &head, NULL, &errp); - g_assert(!errp); + visit_type_UserDefOneList(v, &head, NULL, &err); + g_assert(!err); g_assert(head != NULL); for (i = 0, item = head; item; item = item->next, i++) { @@ -634,16 +641,16 @@ static void test_visitor_in_errors(TestInputVisitorData *data, const void *unused) { TestStruct *p = NULL; - Error *errp = NULL; + Error *err = NULL; Visitor *v; v = visitor_input_test_init(data, "{ 'integer': false, 'boolean': 'foo', 'string': -42 }"); - visit_type_TestStruct(v, &p, NULL, &errp); - g_assert(errp); + visit_type_TestStruct(v, &p, NULL, &err); + g_assert(err); g_assert(p->string == NULL); - error_free(errp); + error_free(err); g_free(p->string); g_free(p); } diff --git a/tests/test-qmp-output-visitor.c b/tests/test-qmp-output-visitor.c index da279713f..74020de5e 100644 --- a/tests/test-qmp-output-visitor.c +++ b/tests/test-qmp-output-visitor.c @@ -45,11 +45,11 @@ static void test_visitor_out_int(TestOutputVisitorData *data, const void *unused) { int64_t value = -42; - Error *errp = NULL; + Error *err = NULL; QObject *obj; - visit_type_int(data->ov, &value, NULL, &errp); - g_assert(!errp); + visit_type_int(data->ov, &value, NULL, &err); + g_assert(!err); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); @@ -62,12 +62,12 @@ static void test_visitor_out_int(TestOutputVisitorData *data, static void test_visitor_out_bool(TestOutputVisitorData *data, const void *unused) { - Error *errp = NULL; + Error *err = NULL; bool value = true; QObject *obj; - visit_type_bool(data->ov, &value, NULL, &errp); - g_assert(!errp); + visit_type_bool(data->ov, &value, NULL, &err); + g_assert(!err); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); @@ -81,11 +81,11 @@ static void test_visitor_out_number(TestOutputVisitorData *data, const void *unused) { double value = 3.14; - Error *errp = NULL; + Error *err = NULL; QObject *obj; - visit_type_number(data->ov, &value, NULL, &errp); - g_assert(!errp); + visit_type_number(data->ov, &value, NULL, &err); + g_assert(!err); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); @@ -99,11 +99,11 @@ static void test_visitor_out_string(TestOutputVisitorData *data, const void *unused) { char *string = (char *) "Q E M U"; - Error *errp = NULL; + Error *err = NULL; QObject *obj; - visit_type_str(data->ov, &string, NULL, &errp); - g_assert(!errp); + visit_type_str(data->ov, &string, NULL, &err); + g_assert(!err); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); @@ -117,12 +117,12 @@ static void test_visitor_out_no_string(TestOutputVisitorData *data, const void *unused) { char *string = NULL; - Error *errp = NULL; + Error *err = NULL; QObject *obj; /* A null string should return "" */ - visit_type_str(data->ov, &string, NULL, &errp); - g_assert(!errp); + visit_type_str(data->ov, &string, NULL, &err); + g_assert(!err); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); @@ -135,13 +135,13 @@ static void test_visitor_out_no_string(TestOutputVisitorData *data, static void test_visitor_out_enum(TestOutputVisitorData *data, const void *unused) { - Error *errp = NULL; + Error *err = NULL; QObject *obj; EnumOne i; for (i = 0; i < ENUM_ONE_MAX; i++) { - visit_type_EnumOne(data->ov, &i, "unused", &errp); - g_assert(!errp); + visit_type_EnumOne(data->ov, &i, "unused", &err); + g_assert(!err); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); @@ -156,13 +156,13 @@ static void test_visitor_out_enum_errors(TestOutputVisitorData *data, const void *unused) { EnumOne i, bad_values[] = { ENUM_ONE_MAX, -1 }; - Error *errp; + Error *err; for (i = 0; i < ARRAY_SIZE(bad_values) ; i++) { - errp = NULL; - visit_type_EnumOne(data->ov, &bad_values[i], "unused", &errp); - g_assert(errp); - error_free(errp); + err = NULL; + visit_type_EnumOne(data->ov, &bad_values[i], "unused", &err); + g_assert(err); + error_free(err); } } @@ -176,14 +176,30 @@ typedef struct TestStruct static void visit_type_TestStruct(Visitor *v, TestStruct **obj, const char *name, Error **errp) { + Error *err = NULL; + visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct), - errp); + &err); + if (err) { + goto out; + } - visit_type_int(v, &(*obj)->integer, "integer", errp); - visit_type_bool(v, &(*obj)->boolean, "boolean", errp); - visit_type_str(v, &(*obj)->string, "string", errp); + visit_type_int(v, &(*obj)->integer, "integer", &err); + if (err) { + goto out_end; + } + visit_type_bool(v, &(*obj)->boolean, "boolean", &err); + if (err) { + goto out_end; + } + visit_type_str(v, &(*obj)->string, "string", &err); - visit_end_struct(v, errp); +out_end: + error_propagate(errp, err); + err = NULL; + visit_end_struct(v, &err); +out: + error_propagate(errp, err); } static void test_visitor_out_struct(TestOutputVisitorData *data, @@ -193,12 +209,12 @@ static void test_visitor_out_struct(TestOutputVisitorData *data, .boolean = false, .string = (char *) "foo"}; TestStruct *p = &test_struct; - Error *errp = NULL; + Error *err = NULL; QObject *obj; QDict *qdict; - visit_type_TestStruct(data->ov, &p, NULL, &errp); - g_assert(!errp); + visit_type_TestStruct(data->ov, &p, NULL, &err); + g_assert(!err); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); @@ -217,7 +233,7 @@ static void test_visitor_out_struct_nested(TestOutputVisitorData *data, const void *unused) { int64_t value = 42; - Error *errp = NULL; + Error *err = NULL; UserDefNested *ud2; QObject *obj; QDict *qdict, *dict1, *dict2, *dict3, *userdef; @@ -242,8 +258,8 @@ static void test_visitor_out_struct_nested(TestOutputVisitorData *data, ud2->dict1.dict3.userdef2->base->integer = value; ud2->dict1.dict3.string3 = g_strdup(strings[3]); - visit_type_UserDefNested(data->ov, &ud2, "unused", &errp); - g_assert(!errp); + visit_type_UserDefNested(data->ov, &ud2, "unused", &err); + g_assert(!err); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); @@ -283,16 +299,16 @@ static void test_visitor_out_struct_errors(TestOutputVisitorData *data, EnumOne bad_values[] = { ENUM_ONE_MAX, -1 }; UserDefZero b; UserDefOne u = { .base = &b }, *pu = &u; - Error *errp; + Error *err; int i; for (i = 0; i < ARRAY_SIZE(bad_values) ; i++) { - errp = NULL; + err = NULL; u.has_enum1 = true; u.enum1 = bad_values[i]; - visit_type_UserDefOne(data->ov, &pu, "unused", &errp); - g_assert(errp); - error_free(errp); + visit_type_UserDefOne(data->ov, &pu, "unused", &err); + g_assert(err); + error_free(err); } } @@ -328,7 +344,7 @@ static void test_visitor_out_list(TestOutputVisitorData *data, const int max_items = 10; bool value_bool = true; int value_int = 10; - Error *errp = NULL; + Error *err = NULL; QListEntry *entry; QObject *obj; QList *qlist; @@ -345,8 +361,8 @@ static void test_visitor_out_list(TestOutputVisitorData *data, head = p; } - visit_type_TestStructList(data->ov, &head, NULL, &errp); - g_assert(!errp); + visit_type_TestStructList(data->ov, &head, NULL, &err); + g_assert(!err); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); @@ -491,6 +507,15 @@ static void test_visitor_out_union_anon(TestOutputVisitorData *data, qapi_free_UserDefAnonUnion(tmp); } +static void test_visitor_out_empty(TestOutputVisitorData *data, + const void *unused) +{ + QObject *arg; + + arg = qmp_output_get_qobject(data->qov); + g_assert(!arg); +} + static void init_native_list(UserDefNativeListUnion *cvalue) { int i; @@ -843,6 +868,8 @@ int main(int argc, char **argv) &out_visitor_data, test_visitor_out_union_flat); output_visitor_test_add("/visitor/output/union-anon", &out_visitor_data, test_visitor_out_union_anon); + output_visitor_test_add("/visitor/output/empty", + &out_visitor_data, test_visitor_out_empty); output_visitor_test_add("/visitor/output/native_list/int", &out_visitor_data, test_visitor_out_native_list_int); output_visitor_test_add("/visitor/output/native_list/int8", diff --git a/tests/test-string-input-visitor.c b/tests/test-string-input-visitor.c index d406263ae..8e3433e0c 100644 --- a/tests/test-string-input-visitor.c +++ b/tests/test-string-input-visitor.c @@ -54,62 +54,89 @@ static void test_visitor_in_int(TestInputVisitorData *data, const void *unused) { int64_t res = 0, value = -42; - Error *errp = NULL; + Error *err = NULL; Visitor *v; v = visitor_input_test_init(data, "-42"); - visit_type_int(v, &res, NULL, &errp); - g_assert(!errp); + visit_type_int(v, &res, NULL, &err); + g_assert(!err); g_assert_cmpint(res, ==, value); } +static void test_visitor_in_intList(TestInputVisitorData *data, + const void *unused) +{ + int64_t value[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 20}; + int16List *res = NULL, *tmp; + Visitor *v; + int i = 0; + + v = visitor_input_test_init(data, "1,2,0,2-4,20,5-9,1-8"); + + visit_type_int16List(v, &res, NULL, &error_abort); + tmp = res; + while (i < sizeof(value) / sizeof(value[0])) { + g_assert(tmp); + g_assert_cmpint(tmp->value, ==, value[i++]); + tmp = tmp->next; + } + g_assert(!tmp); + + tmp = res; + while (tmp) { + res = res->next; + g_free(tmp); + tmp = res; + } +} + static void test_visitor_in_bool(TestInputVisitorData *data, const void *unused) { - Error *errp = NULL; + Error *err = NULL; bool res = false; Visitor *v; v = visitor_input_test_init(data, "true"); - visit_type_bool(v, &res, NULL, &errp); - g_assert(!errp); + visit_type_bool(v, &res, NULL, &err); + g_assert(!err); g_assert_cmpint(res, ==, true); visitor_input_teardown(data, unused); v = visitor_input_test_init(data, "yes"); - visit_type_bool(v, &res, NULL, &errp); - g_assert(!errp); + visit_type_bool(v, &res, NULL, &err); + g_assert(!err); g_assert_cmpint(res, ==, true); visitor_input_teardown(data, unused); v = visitor_input_test_init(data, "on"); - visit_type_bool(v, &res, NULL, &errp); - g_assert(!errp); + visit_type_bool(v, &res, NULL, &err); + g_assert(!err); g_assert_cmpint(res, ==, true); visitor_input_teardown(data, unused); v = visitor_input_test_init(data, "false"); - visit_type_bool(v, &res, NULL, &errp); - g_assert(!errp); + visit_type_bool(v, &res, NULL, &err); + g_assert(!err); g_assert_cmpint(res, ==, false); visitor_input_teardown(data, unused); v = visitor_input_test_init(data, "no"); - visit_type_bool(v, &res, NULL, &errp); - g_assert(!errp); + visit_type_bool(v, &res, NULL, &err); + g_assert(!err); g_assert_cmpint(res, ==, false); visitor_input_teardown(data, unused); v = visitor_input_test_init(data, "off"); - visit_type_bool(v, &res, NULL, &errp); - g_assert(!errp); + visit_type_bool(v, &res, NULL, &err); + g_assert(!err); g_assert_cmpint(res, ==, false); } @@ -117,13 +144,13 @@ static void test_visitor_in_number(TestInputVisitorData *data, const void *unused) { double res = 0, value = 3.14; - Error *errp = NULL; + Error *err = NULL; Visitor *v; v = visitor_input_test_init(data, "3.14"); - visit_type_number(v, &res, NULL, &errp); - g_assert(!errp); + visit_type_number(v, &res, NULL, &err); + g_assert(!err); g_assert_cmpfloat(res, ==, value); } @@ -131,13 +158,13 @@ static void test_visitor_in_string(TestInputVisitorData *data, const void *unused) { char *res = NULL, *value = (char *) "Q E M U"; - Error *errp = NULL; + Error *err = NULL; Visitor *v; v = visitor_input_test_init(data, value); - visit_type_str(v, &res, NULL, &errp); - g_assert(!errp); + visit_type_str(v, &res, NULL, &err); + g_assert(!err); g_assert_cmpstr(res, ==, value); g_free(res); @@ -146,7 +173,7 @@ static void test_visitor_in_string(TestInputVisitorData *data, static void test_visitor_in_enum(TestInputVisitorData *data, const void *unused) { - Error *errp = NULL; + Error *err = NULL; Visitor *v; EnumOne i; @@ -155,8 +182,8 @@ static void test_visitor_in_enum(TestInputVisitorData *data, v = visitor_input_test_init(data, EnumOne_lookup[i]); - visit_type_EnumOne(v, &res, NULL, &errp); - g_assert(!errp); + visit_type_EnumOne(v, &res, NULL, &err); + g_assert(!err); g_assert_cmpint(i, ==, res); visitor_input_teardown(data, NULL); @@ -170,6 +197,7 @@ static void test_visitor_in_fuzz(TestInputVisitorData *data, const void *unused) { int64_t ires; + intList *ilres; bool bres; double nres; char *sres; @@ -193,6 +221,11 @@ static void test_visitor_in_fuzz(TestInputVisitorData *data, v = visitor_input_test_init(data, buf); visit_type_int(v, &ires, NULL, NULL); + visitor_input_teardown(data, NULL); + + v = visitor_input_test_init(data, buf); + visit_type_intList(v, &ilres, NULL, NULL); + visitor_input_teardown(data, NULL); v = visitor_input_test_init(data, buf); visit_type_bool(v, &bres, NULL, NULL); @@ -200,11 +233,13 @@ static void test_visitor_in_fuzz(TestInputVisitorData *data, v = visitor_input_test_init(data, buf); visit_type_number(v, &nres, NULL, NULL); + visitor_input_teardown(data, NULL); v = visitor_input_test_init(data, buf); sres = NULL; visit_type_str(v, &sres, NULL, NULL); g_free(sres); + visitor_input_teardown(data, NULL); v = visitor_input_test_init(data, buf); visit_type_EnumOne(v, &eres, NULL, NULL); @@ -228,6 +263,8 @@ int main(int argc, char **argv) input_visitor_test_add("/string-visitor/input/int", &in_visitor_data, test_visitor_in_int); + input_visitor_test_add("/string-visitor/input/intList", + &in_visitor_data, test_visitor_in_intList); input_visitor_test_add("/string-visitor/input/bool", &in_visitor_data, test_visitor_in_bool); input_visitor_test_add("/string-visitor/input/number", diff --git a/tests/test-string-output-visitor.c b/tests/test-string-output-visitor.c index 22363d100..101fb27dd 100644 --- a/tests/test-string-output-visitor.c +++ b/tests/test-string-output-visitor.c @@ -21,12 +21,25 @@ typedef struct TestOutputVisitorData { StringOutputVisitor *sov; Visitor *ov; + bool human; } TestOutputVisitorData; static void visitor_output_setup(TestOutputVisitorData *data, const void *unused) { - data->sov = string_output_visitor_new(false); + data->human = false; + data->sov = string_output_visitor_new(data->human); + g_assert(data->sov != NULL); + + data->ov = string_output_get_visitor(data->sov); + g_assert(data->ov != NULL); +} + +static void visitor_output_setup_human(TestOutputVisitorData *data, + const void *unused) +{ + data->human = true; + data->sov = string_output_visitor_new(data->human); g_assert(data->sov != NULL); data->ov = string_output_get_visitor(data->sov); @@ -44,28 +57,71 @@ static void visitor_output_teardown(TestOutputVisitorData *data, static void test_visitor_out_int(TestOutputVisitorData *data, const void *unused) { - int64_t value = -42; + int64_t value = 42; + Error *err = NULL; + char *str; + + visit_type_int(data->ov, &value, NULL, &err); + g_assert(!err); + + str = string_output_get_string(data->sov); + g_assert(str != NULL); + if (data->human) { + g_assert_cmpstr(str, ==, "42 (0x2a)"); + } else { + g_assert_cmpstr(str, ==, "42"); + } + g_free(str); +} + +static void test_visitor_out_intList(TestOutputVisitorData *data, + const void *unused) +{ + int64_t value[] = {0, 1, 9, 10, 16, 15, 14, + 3, 4, 5, 6, 11, 12, 13, 21, 22, INT64_MAX - 1, INT64_MAX}; + intList *list = NULL, **tmp = &list; + int i; Error *errp = NULL; char *str; - visit_type_int(data->ov, &value, NULL, &errp); - g_assert(!errp); + for (i = 0; i < sizeof(value) / sizeof(value[0]); i++) { + *tmp = g_malloc0(sizeof(**tmp)); + (*tmp)->value = value[i]; + tmp = &(*tmp)->next; + } + + visit_type_intList(data->ov, &list, NULL, &errp); + g_assert(errp == NULL); str = string_output_get_string(data->sov); g_assert(str != NULL); - g_assert_cmpstr(str, ==, "-42"); + if (data->human) { + g_assert_cmpstr(str, ==, + "0-1,3-6,9-16,21-22,9223372036854775806-9223372036854775807 " + "(0x0-0x1,0x3-0x6,0x9-0x10,0x15-0x16," + "0x7ffffffffffffffe-0x7fffffffffffffff)"); + } else { + g_assert_cmpstr(str, ==, + "0-1,3-6,9-16,21-22,9223372036854775806-9223372036854775807"); + } g_free(str); + while (list) { + intList *tmp2; + tmp2 = list->next; + g_free(list); + list = tmp2; + } } static void test_visitor_out_bool(TestOutputVisitorData *data, const void *unused) { - Error *errp = NULL; + Error *err = NULL; bool value = true; char *str; - visit_type_bool(data->ov, &value, NULL, &errp); - g_assert(!errp); + visit_type_bool(data->ov, &value, NULL, &err); + g_assert(!err); str = string_output_get_string(data->sov); g_assert(str != NULL); @@ -77,11 +133,11 @@ static void test_visitor_out_number(TestOutputVisitorData *data, const void *unused) { double value = 3.14; - Error *errp = NULL; + Error *err = NULL; char *str; - visit_type_number(data->ov, &value, NULL, &errp); - g_assert(!errp); + visit_type_number(data->ov, &value, NULL, &err); + g_assert(!err); str = string_output_get_string(data->sov); g_assert(str != NULL); @@ -93,15 +149,20 @@ static void test_visitor_out_string(TestOutputVisitorData *data, const void *unused) { char *string = (char *) "Q E M U"; - Error *errp = NULL; + const char *string_human = "\"Q E M U\""; + Error *err = NULL; char *str; - visit_type_str(data->ov, &string, NULL, &errp); - g_assert(!errp); + visit_type_str(data->ov, &string, NULL, &err); + g_assert(!err); str = string_output_get_string(data->sov); g_assert(str != NULL); - g_assert_cmpstr(str, ==, string); + if (data->human) { + g_assert_cmpstr(str, ==, string_human); + } else { + g_assert_cmpstr(str, ==, string); + } g_free(str); } @@ -109,33 +170,46 @@ static void test_visitor_out_no_string(TestOutputVisitorData *data, const void *unused) { char *string = NULL; - Error *errp = NULL; + Error *err = NULL; char *str; /* A null string should return "" */ - visit_type_str(data->ov, &string, NULL, &errp); - g_assert(!errp); + visit_type_str(data->ov, &string, NULL, &err); + g_assert(!err); str = string_output_get_string(data->sov); g_assert(str != NULL); - g_assert_cmpstr(str, ==, ""); + if (data->human) { + g_assert_cmpstr(str, ==, "<null>"); + } else { + g_assert_cmpstr(str, ==, ""); + } g_free(str); } static void test_visitor_out_enum(TestOutputVisitorData *data, const void *unused) { - Error *errp = NULL; + Error *err = NULL; char *str; EnumOne i; for (i = 0; i < ENUM_ONE_MAX; i++) { - visit_type_EnumOne(data->ov, &i, "unused", &errp); - g_assert(!errp); + char *str_human; + + visit_type_EnumOne(data->ov, &i, "unused", &err); + g_assert(!err); + + str_human = g_strdup_printf("\"%s\"", EnumOne_lookup[i]); str = string_output_get_string(data->sov); g_assert(str != NULL); - g_assert_cmpstr(str, ==, EnumOne_lookup[i]); + if (data->human) { + g_assert_cmpstr(str, ==, str_human); + } else { + g_assert_cmpstr(str, ==, EnumOne_lookup[i]); + } + g_free(str_human); g_free(str); } } @@ -144,21 +218,25 @@ static void test_visitor_out_enum_errors(TestOutputVisitorData *data, const void *unused) { EnumOne i, bad_values[] = { ENUM_ONE_MAX, -1 }; - Error *errp; + Error *err; for (i = 0; i < ARRAY_SIZE(bad_values) ; i++) { - errp = NULL; - visit_type_EnumOne(data->ov, &bad_values[i], "unused", &errp); - g_assert(errp); - error_free(errp); + err = NULL; + visit_type_EnumOne(data->ov, &bad_values[i], "unused", &err); + g_assert(err); + error_free(err); } } -static void output_visitor_test_add(const char *testpath, - TestOutputVisitorData *data, - void (*test_func)(TestOutputVisitorData *data, const void *user_data)) +static void +output_visitor_test_add(const char *testpath, + TestOutputVisitorData *data, + void (*test_func)(TestOutputVisitorData *data, + const void *user_data), + bool human) { - g_test_add(testpath, TestOutputVisitorData, data, visitor_output_setup, + g_test_add(testpath, TestOutputVisitorData, data, + human ? visitor_output_setup_human : visitor_output_setup, test_func, visitor_output_teardown); } @@ -169,19 +247,41 @@ int main(int argc, char **argv) g_test_init(&argc, &argv, NULL); output_visitor_test_add("/string-visitor/output/int", - &out_visitor_data, test_visitor_out_int); + &out_visitor_data, test_visitor_out_int, false); + output_visitor_test_add("/string-visitor/output/int", + &out_visitor_data, test_visitor_out_int, true); output_visitor_test_add("/string-visitor/output/bool", - &out_visitor_data, test_visitor_out_bool); + &out_visitor_data, test_visitor_out_bool, false); + output_visitor_test_add("/string-visitor/output/bool", + &out_visitor_data, test_visitor_out_bool, true); + output_visitor_test_add("/string-visitor/output/number", + &out_visitor_data, test_visitor_out_number, false); output_visitor_test_add("/string-visitor/output/number", - &out_visitor_data, test_visitor_out_number); + &out_visitor_data, test_visitor_out_number, true); output_visitor_test_add("/string-visitor/output/string", - &out_visitor_data, test_visitor_out_string); + &out_visitor_data, test_visitor_out_string, false); + output_visitor_test_add("/string-visitor/output/string", + &out_visitor_data, test_visitor_out_string, true); + output_visitor_test_add("/string-visitor/output/no-string", + &out_visitor_data, test_visitor_out_no_string, + false); output_visitor_test_add("/string-visitor/output/no-string", - &out_visitor_data, test_visitor_out_no_string); + &out_visitor_data, test_visitor_out_no_string, + true); output_visitor_test_add("/string-visitor/output/enum", - &out_visitor_data, test_visitor_out_enum); + &out_visitor_data, test_visitor_out_enum, false); + output_visitor_test_add("/string-visitor/output/enum", + &out_visitor_data, test_visitor_out_enum, true); + output_visitor_test_add("/string-visitor/output/enum-errors", + &out_visitor_data, test_visitor_out_enum_errors, + false); output_visitor_test_add("/string-visitor/output/enum-errors", - &out_visitor_data, test_visitor_out_enum_errors); + &out_visitor_data, test_visitor_out_enum_errors, + true); + output_visitor_test_add("/string-visitor/output/intList", + &out_visitor_data, test_visitor_out_intList, false); + output_visitor_test_add("/string-visitor/output/intList", + &out_visitor_data, test_visitor_out_intList, true); g_test_run(); diff --git a/tests/test-thread-pool.c b/tests/test-thread-pool.c index c1f8e13a9..f40b7fc17 100644 --- a/tests/test-thread-pool.c +++ b/tests/test-thread-pool.c @@ -83,7 +83,7 @@ static void co_test_cb(void *opaque) data->ret = 0; active--; - /* The test continues in test_submit_co, after qemu_aio_wait_all... */ + /* The test continues in test_submit_co, after aio_poll... */ } static void test_submit_co(void) @@ -98,7 +98,7 @@ static void test_submit_co(void) g_assert_cmpint(active, ==, 1); g_assert_cmpint(data.ret, ==, -EINPROGRESS); - /* qemu_aio_wait_all will execute the rest of the coroutine. */ + /* aio_poll will execute the rest of the coroutine. */ while (data.ret == -EINPROGRESS) { aio_poll(ctx, true); @@ -180,7 +180,7 @@ static void test_cancel(void) /* Canceling the others will be a blocking operation. */ for (i = 0; i < 100; i++) { - if (data[i].n != 3) { + if (data[i].aiocb && data[i].n != 3) { bdrv_aio_cancel(data[i].aiocb); } } diff --git a/tests/test-throttle.c b/tests/test-throttle.c index 1d4ffd360..000ae31af 100644 --- a/tests/test-throttle.c +++ b/tests/test-throttle.c @@ -12,11 +12,13 @@ #include <glib.h> #include <math.h> +#include "block/aio.h" #include "qemu/throttle.h" -LeakyBucket bkt; -ThrottleConfig cfg; -ThrottleState ts; +static AioContext *ctx; +static LeakyBucket bkt; +static ThrottleConfig cfg; +static ThrottleState ts; /* useful function */ static bool double_cmp(double x, double y) @@ -104,7 +106,8 @@ static void test_init(void) memset(&ts, 1, sizeof(ts)); /* init the structure */ - throttle_init(&ts, QEMU_CLOCK_VIRTUAL, read_timer_cb, write_timer_cb, &ts); + throttle_init(&ts, ctx, QEMU_CLOCK_VIRTUAL, + read_timer_cb, write_timer_cb, &ts); /* check initialized fields */ g_assert(ts.clock_type == QEMU_CLOCK_VIRTUAL); @@ -126,7 +129,8 @@ static void test_init(void) static void test_destroy(void) { int i; - throttle_init(&ts, QEMU_CLOCK_VIRTUAL, read_timer_cb, write_timer_cb, &ts); + throttle_init(&ts, ctx, QEMU_CLOCK_VIRTUAL, + read_timer_cb, write_timer_cb, &ts); throttle_destroy(&ts); for (i = 0; i < 2; i++) { g_assert(!ts.timers[i]); @@ -165,7 +169,8 @@ static void test_config_functions(void) orig_cfg.op_size = 1; - throttle_init(&ts, QEMU_CLOCK_VIRTUAL, read_timer_cb, write_timer_cb, &ts); + throttle_init(&ts, ctx, QEMU_CLOCK_VIRTUAL, + read_timer_cb, write_timer_cb, &ts); /* structure reset by throttle_init previous_leak should be null */ g_assert(!ts.previous_leak); throttle_config(&ts, &orig_cfg); @@ -324,7 +329,8 @@ static void test_have_timer(void) g_assert(!throttle_have_timer(&ts)); /* init the structure */ - throttle_init(&ts, QEMU_CLOCK_VIRTUAL, read_timer_cb, write_timer_cb, &ts); + throttle_init(&ts, ctx, QEMU_CLOCK_VIRTUAL, + read_timer_cb, write_timer_cb, &ts); /* timer set by init should return true */ g_assert(throttle_have_timer(&ts)); @@ -332,6 +338,29 @@ static void test_have_timer(void) throttle_destroy(&ts); } +static void test_detach_attach(void) +{ + /* zero the structure */ + memset(&ts, 0, sizeof(ts)); + + /* init the structure */ + throttle_init(&ts, ctx, QEMU_CLOCK_VIRTUAL, + read_timer_cb, write_timer_cb, &ts); + + /* timer set by init should return true */ + g_assert(throttle_have_timer(&ts)); + + /* timer should no longer exist after detaching */ + throttle_detach_aio_context(&ts); + g_assert(!throttle_have_timer(&ts)); + + /* timer should exist again after attaching */ + throttle_attach_aio_context(&ts, ctx); + g_assert(throttle_have_timer(&ts)); + + throttle_destroy(&ts); +} + static bool do_test_accounting(bool is_ops, /* are we testing bps or ops */ int size, /* size of the operation to do */ double avg, /* io limit */ @@ -357,7 +386,8 @@ static bool do_test_accounting(bool is_ops, /* are we testing bps or ops */ cfg.op_size = op_size; - throttle_init(&ts, QEMU_CLOCK_VIRTUAL, read_timer_cb, write_timer_cb, &ts); + throttle_init(&ts, ctx, QEMU_CLOCK_VIRTUAL, + read_timer_cb, write_timer_cb, &ts); throttle_config(&ts, &cfg); /* account a read */ @@ -461,7 +491,15 @@ static void test_accounting(void) int main(int argc, char **argv) { + GSource *src; + init_clocks(); + + ctx = aio_context_new(); + src = aio_get_g_source(ctx); + g_source_attach(src, NULL); + g_source_unref(src); + do {} while (g_main_context_iteration(NULL, false)); /* tests in the same order as the header function declarations */ @@ -471,6 +509,7 @@ int main(int argc, char **argv) g_test_add_func("/throttle/init", test_init); g_test_add_func("/throttle/destroy", test_destroy); g_test_add_func("/throttle/have_timer", test_have_timer); + g_test_add_func("/throttle/detach_attach", test_detach_attach); g_test_add_func("/throttle/config/enabled", test_enabled); g_test_add_func("/throttle/config/conflicting", test_conflicting_config); g_test_add_func("/throttle/config/is_valid", test_is_valid); diff --git a/tests/test-visitor-serialization.c b/tests/test-visitor-serialization.c index 8166cf1b0..7ad188639 100644 --- a/tests/test-visitor-serialization.c +++ b/tests/test-visitor-serialization.c @@ -195,13 +195,29 @@ typedef struct TestStruct static void visit_type_TestStruct(Visitor *v, TestStruct **obj, const char *name, Error **errp) { - visit_start_struct(v, (void **)obj, NULL, name, sizeof(TestStruct), errp); + Error *err = NULL; - visit_type_int(v, &(*obj)->integer, "integer", errp); - visit_type_bool(v, &(*obj)->boolean, "boolean", errp); - visit_type_str(v, &(*obj)->string, "string", errp); + visit_start_struct(v, (void **)obj, NULL, name, sizeof(TestStruct), &err); + if (err) { + goto out; + } - visit_end_struct(v, errp); + visit_type_int(v, &(*obj)->integer, "integer", &err); + if (err) { + goto out_end; + } + visit_type_bool(v, &(*obj)->boolean, "boolean", &err); + if (err) { + goto out_end; + } + visit_type_str(v, &(*obj)->string, "string", &err); + +out_end: + error_propagate(errp, err); + err = NULL; + visit_end_struct(v, &err); +out: + error_propagate(errp, err); } static TestStruct *struct_create(void) @@ -356,8 +372,8 @@ static void test_primitive_lists(gconstpointer opaque) TestArgs *args = (TestArgs *) opaque; const SerializeOps *ops = args->ops; PrimitiveType *pt = args->test_data; - PrimitiveList pl = { .value = { 0 } }; - PrimitiveList pl_copy = { .value = { 0 } }; + PrimitiveList pl = { .value = { NULL } }; + PrimitiveList pl_copy = { .value = { NULL } }; PrimitiveList *pl_copy_ptr = &pl_copy; Error *err = NULL; void *serialize_data; @@ -755,7 +771,7 @@ static void test_nested_struct_list(gconstpointer opaque) g_free(args); } -PrimitiveType pt_values[] = { +static PrimitiveType pt_values[] = { /* string tests */ { .description = "string_empty", diff --git a/tests/test-vmstate.c b/tests/test-vmstate.c index 75cd1a1fd..d72c64c90 100644 --- a/tests/test-vmstate.c +++ b/tests/test-vmstate.c @@ -29,8 +29,8 @@ #include "migration/vmstate.h" #include "block/coroutine.h" -char temp_file[] = "/tmp/vmst.test.XXXXXX"; -int temp_fd; +static char temp_file[] = "/tmp/vmst.test.XXXXXX"; +static int temp_fd; /* Fake yield_until_fd_readable() implementation so we don't have to pull the * coroutine code as dependency. @@ -44,95 +44,245 @@ void yield_until_fd_readable(int fd) } /* Duplicate temp_fd and seek to the beginning of the file */ -static int dup_temp_fd(bool truncate) +static QEMUFile *open_test_file(bool write) { int fd = dup(temp_fd); lseek(fd, 0, SEEK_SET); - if (truncate) { + if (write) { g_assert_cmpint(ftruncate(fd, 0), ==, 0); } - return fd; + return qemu_fdopen(fd, write ? "wb" : "rb"); } -typedef struct TestSruct { - uint32_t a, b, c, e; - uint64_t d, f; - bool skip_c_e; -} TestStruct; +#define SUCCESS(val) \ + g_assert_cmpint((val), ==, 0) +#define FAILURE(val) \ + g_assert_cmpint((val), !=, 0) -static const VMStateDescription vmstate_simple = { - .name = "test", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(a, TestStruct), - VMSTATE_UINT32(b, TestStruct), - VMSTATE_UINT32(c, TestStruct), - VMSTATE_UINT64(d, TestStruct), - VMSTATE_END_OF_LIST() - } -}; +static void save_vmstate(const VMStateDescription *desc, void *obj) +{ + QEMUFile *f = open_test_file(true); + + /* Save file with vmstate */ + vmstate_save_state(f, desc, obj); + qemu_put_byte(f, QEMU_VM_EOF); + g_assert(!qemu_file_get_error(f)); + qemu_fclose(f); +} -static void test_simple_save(void) +static void compare_vmstate(uint8_t *wire, size_t size) { - QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb"); - TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4 }; - vmstate_save_state(fsave, &vmstate_simple, &obj); - g_assert(!qemu_file_get_error(fsave)); - qemu_fclose(fsave); + QEMUFile *f = open_test_file(false); + uint8_t result[size]; - QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb"); - uint8_t expected[] = { - 0, 0, 0, 1, /* a */ - 0, 0, 0, 2, /* b */ - 0, 0, 0, 3, /* c */ - 0, 0, 0, 0, 0, 0, 0, 4, /* d */ - }; - uint8_t result[sizeof(expected)]; - g_assert_cmpint(qemu_get_buffer(loading, result, sizeof(result)), ==, + /* read back as binary */ + + g_assert_cmpint(qemu_get_buffer(f, result, sizeof(result)), ==, sizeof(result)); - g_assert(!qemu_file_get_error(loading)); - g_assert_cmpint(memcmp(result, expected, sizeof(result)), ==, 0); + g_assert(!qemu_file_get_error(f)); + + /* Compare that what is on the file is the same that what we + expected to be there */ + SUCCESS(memcmp(result, wire, sizeof(result))); /* Must reach EOF */ - qemu_get_byte(loading); - g_assert_cmpint(qemu_file_get_error(loading), ==, -EIO); + qemu_get_byte(f); + g_assert_cmpint(qemu_file_get_error(f), ==, -EIO); - qemu_fclose(loading); + qemu_fclose(f); } -static void test_simple_load(void) +static int load_vmstate_one(const VMStateDescription *desc, void *obj, + int version, uint8_t *wire, size_t size) { - QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb"); - uint8_t buf[] = { - 0, 0, 0, 10, /* a */ - 0, 0, 0, 20, /* b */ - 0, 0, 0, 30, /* c */ - 0, 0, 0, 0, 0, 0, 0, 40, /* d */ - QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */ - }; - qemu_put_buffer(fsave, buf, sizeof(buf)); - qemu_fclose(fsave); + QEMUFile *f; + int ret; + + f = open_test_file(true); + qemu_put_buffer(f, wire, size); + qemu_fclose(f); + + f = open_test_file(false); + ret = vmstate_load_state(f, desc, obj, version); + if (ret) { + g_assert(qemu_file_get_error(f)); + } else{ + g_assert(!qemu_file_get_error(f)); + } + qemu_fclose(f); + return ret; +} - QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb"); - TestStruct obj; - vmstate_load_state(loading, &vmstate_simple, &obj, 1); - g_assert(!qemu_file_get_error(loading)); - g_assert_cmpint(obj.a, ==, 10); - g_assert_cmpint(obj.b, ==, 20); - g_assert_cmpint(obj.c, ==, 30); - g_assert_cmpint(obj.d, ==, 40); - qemu_fclose(loading); + +static int load_vmstate(const VMStateDescription *desc, + void *obj, void *obj_clone, + void (*obj_copy)(void *, void*), + int version, uint8_t *wire, size_t size) +{ + /* We test with zero size */ + obj_copy(obj_clone, obj); + FAILURE(load_vmstate_one(desc, obj, version, wire, 0)); + + /* Stream ends with QEMU_EOF, so we need at least 3 bytes to be + * able to test in the middle */ + + if (size > 3) { + + /* We test with size - 2. We can't test size - 1 due to EOF tricks */ + obj_copy(obj, obj_clone); + FAILURE(load_vmstate_one(desc, obj, version, wire, size - 2)); + + /* Test with size/2, first half of real state */ + obj_copy(obj, obj_clone); + FAILURE(load_vmstate_one(desc, obj, version, wire, size/2)); + + /* Test with size/2, second half of real state */ + obj_copy(obj, obj_clone); + FAILURE(load_vmstate_one(desc, obj, version, wire + (size/2), size/2)); + + } + obj_copy(obj, obj_clone); + return load_vmstate_one(desc, obj, version, wire, size); } +/* Test struct that we are going to use for our tests */ + +typedef struct TestSimple { + bool b_1, b_2; + uint8_t u8_1; + uint16_t u16_1; + uint32_t u32_1; + uint64_t u64_1; + int8_t i8_1, i8_2; + int16_t i16_1, i16_2; + int32_t i32_1, i32_2; + int64_t i64_1, i64_2; +} TestSimple; + +/* Object instantiation, we are going to use it in more than one test */ + +TestSimple obj_simple = { + .b_1 = true, + .b_2 = false, + .u8_1 = 130, + .u16_1 = 512, + .u32_1 = 70000, + .u64_1 = 12121212, + .i8_1 = 65, + .i8_2 = -65, + .i16_1 = 512, + .i16_2 = -512, + .i32_1 = 70000, + .i32_2 = -70000, + .i64_1 = 12121212, + .i64_2 = -12121212, +}; + +/* Description of the values. If you add a primitive type + you are expected to add a test here */ + +static const VMStateDescription vmstate_simple_primitive = { + .name = "simple/primitive", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_BOOL(b_1, TestSimple), + VMSTATE_BOOL(b_2, TestSimple), + VMSTATE_UINT8(u8_1, TestSimple), + VMSTATE_UINT16(u16_1, TestSimple), + VMSTATE_UINT32(u32_1, TestSimple), + VMSTATE_UINT64(u64_1, TestSimple), + VMSTATE_INT8(i8_1, TestSimple), + VMSTATE_INT8(i8_2, TestSimple), + VMSTATE_INT16(i16_1, TestSimple), + VMSTATE_INT16(i16_2, TestSimple), + VMSTATE_INT32(i32_1, TestSimple), + VMSTATE_INT32(i32_2, TestSimple), + VMSTATE_INT64(i64_1, TestSimple), + VMSTATE_INT64(i64_2, TestSimple), + VMSTATE_END_OF_LIST() + } +}; + +/* It describes what goes through the wire. Our tests are basically: + + * save test + - save a struct a vmstate to a file + - read that file back (binary read, no vmstate) + - compare it with what we expect to be on the wire + * load test + - save to the file what we expect to be on the wire + - read struct back with vmstate in a different + - compare back with the original struct +*/ + +uint8_t wire_simple_primitive[] = { + /* b_1 */ 0x01, + /* b_2 */ 0x00, + /* u8_1 */ 0x82, + /* u16_1 */ 0x02, 0x00, + /* u32_1 */ 0x00, 0x01, 0x11, 0x70, + /* u64_1 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xf4, 0x7c, + /* i8_1 */ 0x41, + /* i8_2 */ 0xbf, + /* i16_1 */ 0x02, 0x00, + /* i16_2 */ 0xfe, 0x0, + /* i32_1 */ 0x00, 0x01, 0x11, 0x70, + /* i32_2 */ 0xff, 0xfe, 0xee, 0x90, + /* i64_1 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xf4, 0x7c, + /* i64_2 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0x47, 0x0b, 0x84, + QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */ +}; + +static void obj_simple_copy(void *target, void *source) +{ + memcpy(target, source, sizeof(TestSimple)); +} + +static void test_simple_primitive(void) +{ + TestSimple obj, obj_clone; + + memset(&obj, 0, sizeof(obj)); + save_vmstate(&vmstate_simple_primitive, &obj_simple); + + compare_vmstate(wire_simple_primitive, sizeof(wire_simple_primitive)); + + SUCCESS(load_vmstate(&vmstate_simple_primitive, &obj, &obj_clone, + obj_simple_copy, 1, wire_simple_primitive, + sizeof(wire_simple_primitive))); + +#define FIELD_EQUAL(name) g_assert_cmpint(obj.name, ==, obj_simple.name) + + FIELD_EQUAL(b_1); + FIELD_EQUAL(b_2); + FIELD_EQUAL(u8_1); + FIELD_EQUAL(u16_1); + FIELD_EQUAL(u32_1); + FIELD_EQUAL(u64_1); + FIELD_EQUAL(i8_1); + FIELD_EQUAL(i8_2); + FIELD_EQUAL(i16_1); + FIELD_EQUAL(i16_2); + FIELD_EQUAL(i32_1); + FIELD_EQUAL(i32_2); + FIELD_EQUAL(i64_1); + FIELD_EQUAL(i64_2); +} +#undef FIELD_EQUAL + +typedef struct TestStruct { + uint32_t a, b, c, e; + uint64_t d, f; + bool skip_c_e; +} TestStruct; + static const VMStateDescription vmstate_versioned = { - .name = "test", + .name = "test/versioned", .version_id = 2, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT32(a, TestStruct), VMSTATE_UINT32_V(b, TestStruct, 2), /* Versioned field in the middle, so * we catch bugs more easily. @@ -147,7 +297,7 @@ static const VMStateDescription vmstate_versioned = { static void test_load_v1(void) { - QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb"); + QEMUFile *fsave = open_test_file(true); uint8_t buf[] = { 0, 0, 0, 10, /* a */ 0, 0, 0, 30, /* c */ @@ -157,7 +307,7 @@ static void test_load_v1(void) qemu_put_buffer(fsave, buf, sizeof(buf)); qemu_fclose(fsave); - QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb"); + QEMUFile *loading = open_test_file(false); TestStruct obj = { .b = 200, .e = 500, .f = 600 }; vmstate_load_state(loading, &vmstate_versioned, &obj, 1); g_assert(!qemu_file_get_error(loading)); @@ -172,7 +322,7 @@ static void test_load_v1(void) static void test_load_v2(void) { - QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb"); + QEMUFile *fsave = open_test_file(true); uint8_t buf[] = { 0, 0, 0, 10, /* a */ 0, 0, 0, 20, /* b */ @@ -185,7 +335,7 @@ static void test_load_v2(void) qemu_put_buffer(fsave, buf, sizeof(buf)); qemu_fclose(fsave); - QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb"); + QEMUFile *loading = open_test_file(false); TestStruct obj; vmstate_load_state(loading, &vmstate_versioned, &obj, 2); g_assert_cmpint(obj.a, ==, 10); @@ -204,11 +354,10 @@ static bool test_skip(void *opaque, int version_id) } static const VMStateDescription vmstate_skipping = { - .name = "test", + .name = "test/skip", .version_id = 2, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT32(a, TestStruct), VMSTATE_UINT32(b, TestStruct), VMSTATE_UINT32_TEST(c, TestStruct, test_skip), @@ -222,14 +371,14 @@ static const VMStateDescription vmstate_skipping = { static void test_save_noskip(void) { - QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb"); + QEMUFile *fsave = open_test_file(true); TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4, .e = 5, .f = 6, .skip_c_e = false }; vmstate_save_state(fsave, &vmstate_skipping, &obj); g_assert(!qemu_file_get_error(fsave)); qemu_fclose(fsave); - QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb"); + QEMUFile *loading = open_test_file(false); uint8_t expected[] = { 0, 0, 0, 1, /* a */ 0, 0, 0, 2, /* b */ @@ -253,14 +402,14 @@ static void test_save_noskip(void) static void test_save_skip(void) { - QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb"); + QEMUFile *fsave = open_test_file(true); TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4, .e = 5, .f = 6, .skip_c_e = true }; vmstate_save_state(fsave, &vmstate_skipping, &obj); g_assert(!qemu_file_get_error(fsave)); qemu_fclose(fsave); - QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb"); + QEMUFile *loading = open_test_file(false); uint8_t expected[] = { 0, 0, 0, 1, /* a */ 0, 0, 0, 2, /* b */ @@ -283,7 +432,7 @@ static void test_save_skip(void) static void test_load_noskip(void) { - QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb"); + QEMUFile *fsave = open_test_file(true); uint8_t buf[] = { 0, 0, 0, 10, /* a */ 0, 0, 0, 20, /* b */ @@ -296,7 +445,7 @@ static void test_load_noskip(void) qemu_put_buffer(fsave, buf, sizeof(buf)); qemu_fclose(fsave); - QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb"); + QEMUFile *loading = open_test_file(false); TestStruct obj = { .skip_c_e = false }; vmstate_load_state(loading, &vmstate_skipping, &obj, 2); g_assert(!qemu_file_get_error(loading)); @@ -311,7 +460,7 @@ static void test_load_noskip(void) static void test_load_skip(void) { - QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb"); + QEMUFile *fsave = open_test_file(true); uint8_t buf[] = { 0, 0, 0, 10, /* a */ 0, 0, 0, 20, /* b */ @@ -322,7 +471,7 @@ static void test_load_skip(void) qemu_put_buffer(fsave, buf, sizeof(buf)); qemu_fclose(fsave); - QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb"); + QEMUFile *loading = open_test_file(false); TestStruct obj = { .skip_c_e = true, .c = 300, .e = 500 }; vmstate_load_state(loading, &vmstate_skipping, &obj, 2); g_assert(!qemu_file_get_error(loading)); @@ -340,8 +489,7 @@ int main(int argc, char **argv) temp_fd = mkstemp(temp_file); g_test_init(&argc, &argv, NULL); - g_test_add_func("/vmstate/simple/save", test_simple_save); - g_test_add_func("/vmstate/simple/load", test_simple_load); + g_test_add_func("/vmstate/simple/primitive", test_simple_primitive); g_test_add_func("/vmstate/versioned/load/v1", test_load_v1); g_test_add_func("/vmstate/versioned/load/v2", test_load_v2); g_test_add_func("/vmstate/field_exists/load/noskip", test_load_noskip); diff --git a/tests/tmp105-test.c b/tests/tmp105-test.c index 15ddaf38d..99db53819 100644 --- a/tests/tmp105-test.c +++ b/tests/tmp105-test.c @@ -69,7 +69,7 @@ static int qmp_tmp105_get_temperature(const char *id) QDict *response; int ret; - response = qmp("{ 'execute': 'qom-get', 'arguments': { 'path': '%s', " + response = qmp("{ 'execute': 'qom-get', 'arguments': { 'path': %s, " "'property': 'temperature' } }", id); g_assert(qdict_haskey(response, "return")); ret = qdict_get_int(response, "return"); @@ -81,7 +81,7 @@ static void qmp_tmp105_set_temperature(const char *id, int value) { QDict *response; - response = qmp("{ 'execute': 'qom-set', 'arguments': { 'path': '%s', " + response = qmp("{ 'execute': 'qom-set', 'arguments': { 'path': %s, " "'property': 'temperature', 'value': %d } }", id, value); g_assert(qdict_haskey(response, "return")); QDECREF(response); diff --git a/tests/usb-hcd-ehci-test.c b/tests/usb-hcd-ehci-test.c new file mode 100644 index 000000000..bcdf62fc3 --- /dev/null +++ b/tests/usb-hcd-ehci-test.c @@ -0,0 +1,185 @@ +/* + * QTest testcase for USB EHCI + * + * Copyright (c) 2014 SUSE LINUX Products GmbH + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include <glib.h> +#include <string.h> +#include <stdio.h> +#include "libqtest.h" +#include "libqos/pci-pc.h" +#include "qemu/osdep.h" +#include "hw/usb/uhci-regs.h" +#include "hw/usb/ehci-regs.h" + +struct qhc { + QPCIDevice *dev; + void *base; +}; + +static QPCIBus *pcibus; +static struct qhc uhci1; +static struct qhc uhci2; +static struct qhc uhci3; +static struct qhc ehci1; + +/* helpers */ + +static void pci_init_one(struct qhc *hc, uint32_t devfn, int bar) +{ + hc->dev = qpci_device_find(pcibus, devfn); + g_assert(hc->dev != NULL); + qpci_device_enable(hc->dev); + hc->base = qpci_iomap(hc->dev, bar); + g_assert(hc->base != NULL); +} + +#if 0 +static void uhci_port_update(struct qhc *hc, int port, + uint16_t set, uint16_t clear) +{ + void *addr = hc->base + 0x10 + 2 * port; + uint16_t value; + + value = qpci_io_readw(hc->dev, addr); + value |= set; + value &= ~clear; + qpci_io_writew(hc->dev, addr, value); +} +#endif + +static void uhci_port_test(struct qhc *hc, int port, uint16_t expect) +{ + void *addr = hc->base + 0x10 + 2 * port; + uint16_t value = qpci_io_readw(hc->dev, addr); + uint16_t mask = ~(UHCI_PORT_WRITE_CLEAR | UHCI_PORT_RSVD1); + +#if 0 + fprintf(stderr, "%s: %d, have 0x%04x, want 0x%04x\n", + __func__, port, value & mask, expect & mask); +#endif + g_assert((value & mask) == (expect & mask)); +} + +static void ehci_port_test(struct qhc *hc, int port, uint32_t expect) +{ + void *addr = hc->base + 0x64 + 4 * port; + uint32_t value = qpci_io_readl(hc->dev, addr); + uint16_t mask = ~(PORTSC_CSC | PORTSC_PEDC | PORTSC_OCC); + +#if 0 + fprintf(stderr, "%s: %d, have 0x%08x, want 0x%08x\n", + __func__, port, value & mask, expect & mask); +#endif + g_assert((value & mask) == (expect & mask)); +} + +/* tests */ + +static void pci_init(void) +{ + if (pcibus) { + return; + } + pcibus = qpci_init_pc(); + g_assert(pcibus != NULL); + + pci_init_one(&uhci1, QPCI_DEVFN(0x1d, 0), 4); + pci_init_one(&uhci2, QPCI_DEVFN(0x1d, 1), 4); + pci_init_one(&uhci3, QPCI_DEVFN(0x1d, 2), 4); + pci_init_one(&ehci1, QPCI_DEVFN(0x1d, 7), 0); +} + +static void pci_uhci_port_1(void) +{ + g_assert(pcibus != NULL); + + uhci_port_test(&uhci1, 0, UHCI_PORT_CCS); /* usb-tablet */ + uhci_port_test(&uhci1, 1, UHCI_PORT_CCS); /* usb-storage */ + uhci_port_test(&uhci2, 0, 0); + uhci_port_test(&uhci2, 1, 0); + uhci_port_test(&uhci3, 0, 0); + uhci_port_test(&uhci3, 1, 0); +} + +static void pci_ehci_port_1(void) +{ + int i; + + g_assert(pcibus != NULL); + + for (i = 0; i < 6; i++) { + ehci_port_test(&ehci1, i, PORTSC_POWNER | PORTSC_PPOWER); + } +} + +static void pci_ehci_config(void) +{ + /* hands over all ports from companion uhci to ehci */ + qpci_io_writew(ehci1.dev, ehci1.base + 0x60, 1); +} + +static void pci_uhci_port_2(void) +{ + g_assert(pcibus != NULL); + + uhci_port_test(&uhci1, 0, 0); /* usb-tablet, @ehci */ + uhci_port_test(&uhci1, 1, 0); /* usb-storage, @ehci */ + uhci_port_test(&uhci2, 0, 0); + uhci_port_test(&uhci2, 1, 0); + uhci_port_test(&uhci3, 0, 0); + uhci_port_test(&uhci3, 1, 0); +} + +static void pci_ehci_port_2(void) +{ + static uint32_t expect[] = { + PORTSC_PPOWER | PORTSC_CONNECT, /* usb-tablet */ + PORTSC_PPOWER | PORTSC_CONNECT, /* usb-storage */ + PORTSC_PPOWER, + PORTSC_PPOWER, + PORTSC_PPOWER, + PORTSC_PPOWER, + }; + int i; + + g_assert(pcibus != NULL); + + for (i = 0; i < 6; i++) { + ehci_port_test(&ehci1, i, expect[i]); + } +} + +int main(int argc, char **argv) +{ + int ret; + + g_test_init(&argc, &argv, NULL); + qtest_add_func("/ehci/pci/init", pci_init); + qtest_add_func("/ehci/pci/uhci-port-1", pci_uhci_port_1); + qtest_add_func("/ehci/pci/ehci-port-1", pci_ehci_port_1); + qtest_add_func("/ehci/pci/ehci-config", pci_ehci_config); + qtest_add_func("/ehci/pci/uhci-port-2", pci_uhci_port_2); + qtest_add_func("/ehci/pci/ehci-port-2", pci_ehci_port_2); + + qtest_start("-machine q35 -device ich9-usb-ehci1,bus=pcie.0,addr=1d.7," + "multifunction=on,id=ich9-ehci-1 " + "-device ich9-usb-uhci1,bus=pcie.0,addr=1d.0," + "multifunction=on,masterbus=ich9-ehci-1.0,firstport=0 " + "-device ich9-usb-uhci2,bus=pcie.0,addr=1d.1," + "multifunction=on,masterbus=ich9-ehci-1.0,firstport=2 " + "-device ich9-usb-uhci3,bus=pcie.0,addr=1d.2," + "multifunction=on,masterbus=ich9-ehci-1.0,firstport=4 " + "-drive if=none,id=usbcdrom,media=cdrom " + "-device usb-tablet,bus=ich9-ehci-1.0,port=1,usb_version=1 " + "-device usb-storage,bus=ich9-ehci-1.0,port=2,drive=usbcdrom "); + ret = g_test_run(); + + qtest_end(); + + return ret; +} diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c new file mode 100644 index 000000000..75fedf097 --- /dev/null +++ b/tests/vhost-user-test.c @@ -0,0 +1,421 @@ +/* + * QTest testcase for the vhost-user + * + * Copyright (c) 2014 Virtual Open Systems Sarl. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#define QEMU_GLIB_COMPAT_H +#include <glib.h> + +#include "libqtest.h" +#include "qemu/option.h" +#include "sysemu/char.h" +#include "sysemu/sysemu.h" + +#include <linux/vhost.h> +#include <sys/mman.h> +#include <sys/vfs.h> +#include <qemu/sockets.h> + +/* GLIB version compatibility flags */ +#if !GLIB_CHECK_VERSION(2, 26, 0) +#define G_TIME_SPAN_SECOND (G_GINT64_CONSTANT(1000000)) +#endif + +#if GLIB_CHECK_VERSION(2, 28, 0) +#define HAVE_MONOTONIC_TIME +#endif + +#if GLIB_CHECK_VERSION(2, 32, 0) +#define HAVE_MUTEX_INIT +#define HAVE_COND_INIT +#define HAVE_THREAD_NEW +#endif + +#define QEMU_CMD_ACCEL " -machine accel=tcg" +#define QEMU_CMD_MEM " -m 512 -object memory-backend-file,id=mem,size=512M,"\ + "mem-path=%s,share=on -numa node,memdev=mem" +#define QEMU_CMD_CHR " -chardev socket,id=chr0,path=%s" +#define QEMU_CMD_NETDEV " -netdev vhost-user,id=net0,chardev=chr0,vhostforce" +#define QEMU_CMD_NET " -device virtio-net-pci,netdev=net0 " +#define QEMU_CMD_ROM " -option-rom ../pc-bios/pxe-virtio.rom" + +#define QEMU_CMD QEMU_CMD_ACCEL QEMU_CMD_MEM QEMU_CMD_CHR \ + QEMU_CMD_NETDEV QEMU_CMD_NET QEMU_CMD_ROM + +#define HUGETLBFS_MAGIC 0x958458f6 + +/*********** FROM hw/virtio/vhost-user.c *************************************/ + +#define VHOST_MEMORY_MAX_NREGIONS 8 + +typedef enum VhostUserRequest { + VHOST_USER_NONE = 0, + VHOST_USER_GET_FEATURES = 1, + VHOST_USER_SET_FEATURES = 2, + VHOST_USER_SET_OWNER = 3, + VHOST_USER_RESET_OWNER = 4, + VHOST_USER_SET_MEM_TABLE = 5, + VHOST_USER_SET_LOG_BASE = 6, + VHOST_USER_SET_LOG_FD = 7, + VHOST_USER_SET_VRING_NUM = 8, + VHOST_USER_SET_VRING_ADDR = 9, + VHOST_USER_SET_VRING_BASE = 10, + VHOST_USER_GET_VRING_BASE = 11, + VHOST_USER_SET_VRING_KICK = 12, + VHOST_USER_SET_VRING_CALL = 13, + VHOST_USER_SET_VRING_ERR = 14, + VHOST_USER_MAX +} VhostUserRequest; + +typedef struct VhostUserMemoryRegion { + uint64_t guest_phys_addr; + uint64_t memory_size; + uint64_t userspace_addr; + uint64_t mmap_offset; +} VhostUserMemoryRegion; + +typedef struct VhostUserMemory { + uint32_t nregions; + uint32_t padding; + VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS]; +} VhostUserMemory; + +typedef struct VhostUserMsg { + VhostUserRequest request; + +#define VHOST_USER_VERSION_MASK (0x3) +#define VHOST_USER_REPLY_MASK (0x1<<2) + uint32_t flags; + uint32_t size; /* the following payload size */ + union { + uint64_t u64; + struct vhost_vring_state state; + struct vhost_vring_addr addr; + VhostUserMemory memory; + }; +} QEMU_PACKED VhostUserMsg; + +static VhostUserMsg m __attribute__ ((unused)); +#define VHOST_USER_HDR_SIZE (sizeof(m.request) \ + + sizeof(m.flags) \ + + sizeof(m.size)) + +#define VHOST_USER_PAYLOAD_SIZE (sizeof(m) - VHOST_USER_HDR_SIZE) + +/* The version of the protocol we support */ +#define VHOST_USER_VERSION (0x1) +/*****************************************************************************/ + +int fds_num = 0, fds[VHOST_MEMORY_MAX_NREGIONS]; +static VhostUserMemory memory; +static GMutex *data_mutex; +static GCond *data_cond; + +static gint64 _get_time(void) +{ +#ifdef HAVE_MONOTONIC_TIME + return g_get_monotonic_time(); +#else + GTimeVal time; + g_get_current_time(&time); + + return time.tv_sec * G_TIME_SPAN_SECOND + time.tv_usec; +#endif +} + +static GMutex *_mutex_new(void) +{ + GMutex *mutex; + +#ifdef HAVE_MUTEX_INIT + mutex = g_new(GMutex, 1); + g_mutex_init(mutex); +#else + mutex = g_mutex_new(); +#endif + + return mutex; +} + +static void _mutex_free(GMutex *mutex) +{ +#ifdef HAVE_MUTEX_INIT + g_mutex_clear(mutex); + g_free(mutex); +#else + g_mutex_free(mutex); +#endif +} + +static GCond *_cond_new(void) +{ + GCond *cond; + +#ifdef HAVE_COND_INIT + cond = g_new(GCond, 1); + g_cond_init(cond); +#else + cond = g_cond_new(); +#endif + + return cond; +} + +static gboolean _cond_wait_until(GCond *cond, GMutex *mutex, gint64 end_time) +{ + gboolean ret = FALSE; +#ifdef HAVE_COND_INIT + ret = g_cond_wait_until(cond, mutex, end_time); +#else + GTimeVal time = { end_time / G_TIME_SPAN_SECOND, + end_time % G_TIME_SPAN_SECOND }; + ret = g_cond_timed_wait(cond, mutex, &time); +#endif + return ret; +} + +static void _cond_free(GCond *cond) +{ +#ifdef HAVE_COND_INIT + g_cond_clear(cond); + g_free(cond); +#else + g_cond_free(cond); +#endif +} + +static GThread *_thread_new(const gchar *name, GThreadFunc func, gpointer data) +{ + GThread *thread = NULL; + GError *error = NULL; +#ifdef HAVE_THREAD_NEW + thread = g_thread_try_new(name, func, data, &error); +#else + thread = g_thread_create(func, data, TRUE, &error); +#endif + return thread; +} + +static void read_guest_mem(void) +{ + uint32_t *guest_mem; + gint64 end_time; + int i, j; + size_t size; + + g_mutex_lock(data_mutex); + + end_time = _get_time() + 5 * G_TIME_SPAN_SECOND; + while (!fds_num) { + if (!_cond_wait_until(data_cond, data_mutex, end_time)) { + /* timeout has passed */ + g_assert(fds_num); + break; + } + } + + /* check for sanity */ + g_assert_cmpint(fds_num, >, 0); + g_assert_cmpint(fds_num, ==, memory.nregions); + + /* iterate all regions */ + for (i = 0; i < fds_num; i++) { + + /* We'll check only the region statring at 0x0*/ + if (memory.regions[i].guest_phys_addr != 0x0) { + continue; + } + + g_assert_cmpint(memory.regions[i].memory_size, >, 1024); + + size = memory.regions[i].memory_size + memory.regions[i].mmap_offset; + + guest_mem = mmap(0, size, PROT_READ | PROT_WRITE, + MAP_SHARED, fds[i], 0); + + g_assert(guest_mem != MAP_FAILED); + guest_mem += (memory.regions[i].mmap_offset / sizeof(*guest_mem)); + + for (j = 0; j < 256; j++) { + uint32_t a = readl(memory.regions[i].guest_phys_addr + j*4); + uint32_t b = guest_mem[j]; + + g_assert_cmpint(a, ==, b); + } + + munmap(guest_mem, memory.regions[i].memory_size); + } + + g_assert_cmpint(1, ==, 1); + g_mutex_unlock(data_mutex); +} + +static void *thread_function(void *data) +{ + GMainLoop *loop; + loop = g_main_loop_new(NULL, FALSE); + g_main_loop_run(loop); + return NULL; +} + +static int chr_can_read(void *opaque) +{ + return VHOST_USER_HDR_SIZE; +} + +static void chr_read(void *opaque, const uint8_t *buf, int size) +{ + CharDriverState *chr = opaque; + VhostUserMsg msg; + uint8_t *p = (uint8_t *) &msg; + int fd; + + if (size != VHOST_USER_HDR_SIZE) { + g_test_message("Wrong message size received %d\n", size); + return; + } + + g_mutex_lock(data_mutex); + memcpy(p, buf, VHOST_USER_HDR_SIZE); + + if (msg.size) { + p += VHOST_USER_HDR_SIZE; + qemu_chr_fe_read_all(chr, p, msg.size); + } + + switch (msg.request) { + case VHOST_USER_GET_FEATURES: + /* send back features to qemu */ + msg.flags |= VHOST_USER_REPLY_MASK; + msg.size = sizeof(m.u64); + msg.u64 = 0; + p = (uint8_t *) &msg; + qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size); + break; + + case VHOST_USER_GET_VRING_BASE: + /* send back vring base to qemu */ + msg.flags |= VHOST_USER_REPLY_MASK; + msg.size = sizeof(m.state); + msg.state.num = 0; + p = (uint8_t *) &msg; + qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size); + break; + + case VHOST_USER_SET_MEM_TABLE: + /* received the mem table */ + memcpy(&memory, &msg.memory, sizeof(msg.memory)); + fds_num = qemu_chr_fe_get_msgfds(chr, fds, sizeof(fds) / sizeof(int)); + + /* signal the test that it can continue */ + g_cond_signal(data_cond); + break; + + case VHOST_USER_SET_VRING_KICK: + case VHOST_USER_SET_VRING_CALL: + /* consume the fd */ + qemu_chr_fe_get_msgfds(chr, &fd, 1); + /* + * This is a non-blocking eventfd. + * The receive function forces it to be blocking, + * so revert it back to non-blocking. + */ + qemu_set_nonblock(fd); + break; + default: + break; + } + g_mutex_unlock(data_mutex); +} + +static const char *init_hugepagefs(void) +{ + const char *path; + struct statfs fs; + int ret; + + path = getenv("QTEST_HUGETLBFS_PATH"); + if (!path) { + path = "/hugetlbfs"; + } + + if (access(path, R_OK | W_OK | X_OK)) { + g_test_message("access on path (%s): %s\n", path, strerror(errno)); + return NULL; + } + + do { + ret = statfs(path, &fs); + } while (ret != 0 && errno == EINTR); + + if (ret != 0) { + g_test_message("statfs on path (%s): %s\n", path, strerror(errno)); + return NULL; + } + + if (fs.f_type != HUGETLBFS_MAGIC) { + g_test_message("Warning: path not on HugeTLBFS: %s\n", path); + return NULL; + } + + return path; +} + +int main(int argc, char **argv) +{ + QTestState *s = NULL; + CharDriverState *chr = NULL; + const char *hugefs = 0; + char *socket_path = 0; + char *qemu_cmd = 0; + char *chr_path = 0; + int ret; + + g_test_init(&argc, &argv, NULL); + + module_call_init(MODULE_INIT_QOM); + + hugefs = init_hugepagefs(); + if (!hugefs) { + return 0; + } + + socket_path = g_strdup_printf("/tmp/vhost-%d.sock", getpid()); + + /* create char dev and add read handlers */ + qemu_add_opts(&qemu_chardev_opts); + chr_path = g_strdup_printf("unix:%s,server,nowait", socket_path); + chr = qemu_chr_new("chr0", chr_path, NULL); + g_free(chr_path); + qemu_chr_add_handlers(chr, chr_can_read, chr_read, NULL, chr); + + /* run the main loop thread so the chardev may operate */ + data_mutex = _mutex_new(); + data_cond = _cond_new(); + _thread_new(NULL, thread_function, NULL); + + qemu_cmd = g_strdup_printf(QEMU_CMD, hugefs, socket_path); + s = qtest_start(qemu_cmd); + g_free(qemu_cmd); + + qtest_add_func("/vhost-user/read-guest-mem", read_guest_mem); + + ret = g_test_run(); + + if (s) { + qtest_quit(s); + } + + /* cleanup */ + unlink(socket_path); + g_free(socket_path); + _cond_free(data_cond); + _mutex_free(data_mutex); + + return ret; +} diff --git a/tests/vmstate-static-checker-data/dump1.json b/tests/vmstate-static-checker-data/dump1.json new file mode 100644 index 000000000..786ca0b48 --- /dev/null +++ b/tests/vmstate-static-checker-data/dump1.json @@ -0,0 +1,1163 @@ +{ + "vmschkmachine": { + "Name": "pc-i440fx-2.1" + }, + "fw_cfg": { + "Name": "fw_cfg", + "version_id": 2, + "minimum_version_id": 1, + "Description": { + "name": "fw_cfg", + "version_id": 2, + "minimum_version_id": 1, + "Fields": [ + { + "field": "cur_entry", + "version_id": 0, + "field_exists": false, + "size": 2 + }, + { + "field": "cur_offset", + "version_id": 0, + "field_exists": true, + "size": 4 + }, + { + "field": "cur_offset", + "version_id": 2, + "field_exists": false, + "size": 4 + } + ] + } + }, + "fusbh200-ehci-usb": { + "Name": "fusbh200-ehci-usb", + "version_id": 2, + "minimum_version_id": 1, + "Description": { + "name": "ehci-sysbus", + "version_id": 2, + "minimum_version_id": 1, + "Fields": [ + { + "field": "ehci", + "version_id": 2, + "field_exists": false, + "size": 1880, + "Description": { + "name": "ehci-core", + "version_id": 2, + "minimum_version_id": 1, + "Fields": [ + { + "field": "usbcmd", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "usbsts", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "usbsts_pending", + "version_id": 2, + "field_exists": false, + "size": 4 + }, + { + "field": "usbsts_frindex", + "version_id": 2, + "field_exists": false, + "size": 4 + }, + { + "field": "usbintr", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "frindex", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "ctrldssegment", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "periodiclistbase", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "asynclistaddr", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "configflag", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "portsc[0]", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "portsc[1]", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "portsc[2]", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "portsc[3]", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "portsc[4]", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "portsc[5]", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "frame_timer", + "version_id": 0, + "field_exists": false, + "size": 8 + }, + { + "field": "last_run_ns", + "version_id": 0, + "field_exists": false, + "size": 8 + }, + { + "field": "async_stepdown", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "astate", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "pstate", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "a_fetch_addr", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "p_fetch_addr", + "version_id": 0, + "field_exists": false, + "size": 4 + } + ] + } + } + ] + } + }, + "pci-serial-4x": { + "Name": "pci-serial-4x", + "version_id": 1, + "minimum_version_id": 1, + "Description": { + "name": "pci-serial-multi", + "version_id": 1, + "minimum_version_id": 1, + "Fields": [ + { + "field": "dev", + "version_id": 0, + "field_exists": false, + "size": 1944, + "Description": { + "name": "PCIDevice", + "version_id": 2, + "minimum_version_id": 1, + "Fields": [ + { + "field": "version_id", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "config", + "version_id": 0, + "field_exists": false, + "size": 256 + }, + { + "field": "irq_state", + "version_id": 2, + "field_exists": false, + "size": 16 + } + ] + } + }, + { + "field": "state", + "version_id": 0, + "field_exists": false, + "size": 368, + "Description": { + "name": "serial", + "version_id": 3, + "minimum_version_id": 2, + "Fields": [ + { + "field": "divider", + "version_id": 2, + "field_exists": false, + "size": 2 + }, + { + "field": "rbr", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "ier", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "iir", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "lcr", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "mcr", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "lsr", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "msr", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "scr", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "fcr_vmstate", + "version_id": 3, + "field_exists": false, + "size": 1 + } + ] + } + }, + { + "field": "level", + "version_id": 0, + "field_exists": false, + "size": 4 + } + ] + } + }, + "intel-hda-generic": { + "Name": "intel-hda-generic", + "version_id": 1, + "minimum_version_id": 0, + "Description": { + "name": "intel-hda", + "version_id": 1, + "minimum_version_id": 0, + "Fields": [ + { + "field": "pci", + "version_id": 0, + "field_exists": false, + "size": 1944, + "Description": { + "name": "PCIDevice", + "version_id": 2, + "minimum_version_id": 1, + "Fields": [ + { + "field": "version_id", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "config", + "version_id": 0, + "field_exists": false, + "size": 256 + }, + { + "field": "irq_state", + "version_id": 2, + "field_exists": false, + "size": 16 + } + ] + } + }, + { + "field": "g_ctl", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "wake_en", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "state_sts", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "int_ctl", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "int_sts", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "wall_clk", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "corb_lbase", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "corb_ubase", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "corb_rp", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "corb_wp", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "corb_ctl", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "corb_sts", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "corb_size", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "rirb_lbase", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "rirb_ubase", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "rirb_wp", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "rirb_cnt", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "rirb_ctl", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "rirb_sts", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "rirb_size", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "dp_lbase", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "dp_ubase", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "icw", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "irr", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "ics", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "st", + "version_id": 0, + "field_exists": false, + "size": 56, + "Description": { + "name": "intel-hda-stream", + "version_id": 1, + "minimum_version_id": 0, + "Fields": [ + { + "field": "ctl", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "lpib", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "cbl", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "lvi", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "fmt", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "bdlp_lbase", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "bdlp_ubase", + "version_id": 0, + "field_exists": false, + "size": 4 + } + ] + } + }, + { + "field": "rirb_count", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "wall_base_ns", + "version_id": 0, + "field_exists": false, + "size": 8 + } + ] + } + }, + "cfi.pflash01": { + "Name": "cfi.pflash01", + "version_id": 1, + "minimum_version_id": 1, + "Description": { + "name": "pflash_cfi01", + "version_id": 1, + "minimum_version_id": 1, + "Fields": [ + { + "field": "wcycle", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "cmd", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "status", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "counter", + "version_id": 0, + "field_exists": false, + "size": 8 + } + ] + } + }, + "megasas": { + "Name": "megasas", + "version_id": 0, + "minimum_version_id": 0, + "Description": { + "name": "megasas", + "version_id": 0, + "minimum_version_id": 0, + "Fields": [ + { + "field": "parent_obj", + "version_id": 0, + "field_exists": false, + "size": 1944, + "Description": { + "name": "PCIDevice", + "version_id": 2, + "minimum_version_id": 1, + "Fields": [ + { + "field": "version_id", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "config", + "version_id": 0, + "field_exists": false, + "size": 256 + }, + { + "field": "irq_state", + "version_id": 2, + "field_exists": false, + "size": 16 + } + ] + } + }, + { + "field": "fw_state", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "intr_mask", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "doorbell", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "reply_queue_pa", + "version_id": 0, + "field_exists": false, + "size": 8 + }, + { + "field": "consumer_pa", + "version_id": 0, + "field_exists": false, + "size": 8 + }, + { + "field": "producer_pa", + "version_id": 0, + "field_exists": false, + "size": 8 + } + ] + } + }, + "PIIX3-xen": { + "Name": "PIIX3-xen", + "version_id": 3, + "minimum_version_id": 2, + "Description": { + "name": "PIIX3", + "version_id": 1, + "minimum_version_id": 2, + "Fields": [ + { + "field": "dev", + "version_id": 0, + "field_exists": false, + "size": 1944, + "Description": { + "name": "PCIDevice", + "version_id": 2, + "minimum_version_id": 1, + "Fields": [ + { + "field": "version_id", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "config", + "version_id": 0, + "field_exists": false, + "size": 256 + }, + { + "field": "irq_state", + "version_id": 2, + "field_exists": false, + "size": 16 + } + ] + } + }, + { + "field": "pci_irq_levels_vmstate", + "version_id": 3, + "field_exists": false, + "size": 4 + } + ], + "Subsections": [ + { + "name": "PIIX3/rcr", + "version_id": 1, + "minimum_version_id": 1, + "Fields": [ + { + "field": "rcr", + "version_id": 0, + "field_exists": false, + "size": 1 + } + ] + } + ] + } + }, + "tpci200": { + "Name": "tpci200", + "version_id": 1, + "minimum_version_id": 1, + "Description": { + "name": "tpci200", + "version_id": 1, + "minimum_version_id": 1, + "Fields": [ + { + "field": "dev", + "version_id": 0, + "field_exists": false, + "size": 1944, + "Description": { + "name": "PCIDevice", + "version_id": 2, + "minimum_version_id": 1, + "Fields": [ + { + "field": "version_id", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "config", + "version_id": 0, + "field_exists": false, + "size": 256 + }, + { + "field": "irq_state", + "version_id": 2, + "field_exists": false, + "size": 16 + } + ] + } + }, + { + "field": "big_endian", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "ctrl", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "status", + "version_id": 0, + "field_exists": false, + "size": 2 + }, + { + "field": "int_set", + "version_id": 0, + "field_exists": false, + "size": 1 + } + ] + } + }, + "SUNW,fdtwo": { + "Name": "SUNW,fdtwo", + "version_id": 2, + "minimum_version_id": 2, + "Description": { + "name": "fdc", + "version_id": 2, + "minimum_version_id": 2, + "Fields": [ + { + "field": "state", + "version_id": 0, + "field_exists": false, + "size": 360, + "Description": { + "name": "fdc", + "version_id": 2, + "minimum_version_id": 2, + "Fields": [ + { + "field": "sra", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "srb", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "dor_vmstate", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "tdr", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "dsr", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "msr", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "status0", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "status1", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "status2", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "fifo", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "data_pos", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "data_len", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "data_state", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "data_dir", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "eot", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "timer0", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "timer1", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "precomp_trk", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "config", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "lock", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "pwrd", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "num_floppies", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "drives", + "version_id": 1, + "field_exists": false, + "size": 40, + "Description": { + "name": "fdrive", + "version_id": 1, + "minimum_version_id": 1, + "Fields": [ + { + "field": "head", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "track", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "sect", + "version_id": 0, + "field_exists": false, + "size": 1 + } + ], + "Subsections": [ + { + "name": "fdrive/media_changed", + "version_id": 1, + "minimum_version_id": 1, + "Fields": [ + { + "field": "media_changed", + "version_id": 0, + "field_exists": false, + "size": 1 + } + ] + }, + { + "name": "fdrive/media_rate", + "version_id": 1, + "minimum_version_id": 1, + "Fields": [ + { + "field": "media_rate", + "version_id": 0, + "field_exists": false, + "size": 1 + } + ] + } + ] + } + } + ] + } + } + ] + } + }, + "usb-kbd": { + "Name": "usb-kbd", + "version_id": 1, + "minimum_version_id": 1, + "Description": { + "name": "usb-kbd", + "version_id": 1, + "minimum_version_id": 1, + "Fields": [ + { + "field": "dev", + "version_id": 0, + "field_exists": false, + "size": 4352, + "Description": { + "name": "USBDevice", + "version_id": 1, + "minimum_version_id": 1, + "Fields": [ + { + "field": "addr", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "state", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "remote_wakeup", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "setup_state", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "setup_len", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "setup_index", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "setup_buf", + "version_id": 0, + "field_exists": false, + "size": 1 + } + ] + } + }, + { + "field": "kbd.keycodes", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "head", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "n", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "kbd.modifiers", + "version_id": 0, + "field_exists": false, + "size": 2 + }, + { + "field": "kbd.leds", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "kbd.key", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "kbd.keys", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "protocol", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "idle", + "version_id": 0, + "field_exists": false, + "size": 1 + } + ] + } + } +} diff --git a/tests/vmstate-static-checker-data/dump2.json b/tests/vmstate-static-checker-data/dump2.json new file mode 100644 index 000000000..75719f5ec --- /dev/null +++ b/tests/vmstate-static-checker-data/dump2.json @@ -0,0 +1,968 @@ +{ + "vmschkmachine": { + "Name": "pc-i440fx-2.2" + }, + "fw_cfg2": { + "Name": "fw_cfg", + "version_id": 2, + "minimum_version_id": 1, + "Description": { + "name": "fw_cfg", + "version_id": 2, + "minimum_version_id": 1, + "Fields": [ + { + "field": "cur_entry", + "version_id": 0, + "field_exists": false, + "size": 2 + }, + { + "field": "cur_offset", + "version_id": 0, + "field_exists": true, + "size": 4 + }, + { + "field": "cur_offset", + "version_id": 2, + "field_exists": false, + "size": 4 + } + ] + } + }, + "fusbh200-ehci-usb": { + "Name": "fusbh200-ehci-usb", + "version_id": 1, + "minimum_version_id": 1, + "Description": { + "name": "ehci-sysbus", + "version_id": 2, + "minimum_version_id": 1, + "Fields": [ + { + "field": "ehci", + "version_id": 2, + "field_exists": false, + "size": 1880, + "Description": { + "name": "ehci-core", + "version_id": 2, + "minimum_version_id": 1, + "Fields": [ + { + "field": "usbcmd", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "usbsts_pending", + "version_id": 2, + "field_exists": false, + "size": 4 + }, + { + "field": "usbsts_frindex", + "version_id": 2, + "field_exists": false, + "size": 4 + }, + { + "field": "usbintr", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "frindex", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "ctrldssegment", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "periodiclistbase", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "asynclistaddr", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "configflag", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "portsc[0]", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "portsc[1]", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "portsc[2]", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "portsc[3]", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "portsc[4]", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "portsc[5]", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "frame_timer", + "version_id": 0, + "field_exists": false, + "size": 8 + }, + { + "field": "last_run_ns", + "version_id": 0, + "field_exists": false, + "size": 8 + }, + { + "field": "async_stepdown", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "astate", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "pstate", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "a_fetch_addr", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "p_fetch_addr", + "version_id": 0, + "field_exists": false, + "size": 4 + } + ] + } + } + ] + } + }, + "pci-serial-4x": { + "Name": "pci-serial-4x", + "version_id": 1, + "minimum_version_id": 1, + "Description": { + "name": "pci-serial-multi", + "version_id": 1, + "minimum_version_id": 1 + } + }, + "intel-hda-generic": { + "Name": "intel-hda-generic", + "version_id": 1, + "minimum_version_id": 0, + "Description": { + "name": "intel-hda", + "version_id": 1, + "minimum_version_id": 0, + "Fields": [ + { + "field": "pci", + "version_id": 0, + "field_exists": false, + "size": 1944 + }, + { + "field": "g_ctl", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "wake_en", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "state_sts", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "int_ctl", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "int_sts", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "wall_clk", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "corb_lbase", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "corb_ubase", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "corb_rp", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "corb_wp", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "corb_ctl", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "corb_sts", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "corb_size", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "rirb_lbase", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "rirb_ubase", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "rirb_wp", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "rirb_cnt", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "rirb_ctl", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "rirb_sts", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "rirb_size", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "dp_lbase", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "dp_ubase", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "icw", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "irr", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "ics", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "st", + "version_id": 0, + "field_exists": false, + "size": 56, + "Description": { + "name": "intel-hda-stream", + "version_id": 1, + "minimum_version_id": 0, + "Fields": [ + { + "field": "ctl", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "lpib", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "cbl", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "lvi", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "fmt", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "bdlp_lbase", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "bdlp_ubase", + "version_id": 0, + "field_exists": false, + "size": 4 + } + ] + } + }, + { + "field": "rirb_count", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "wall_base_ns", + "version_id": 0, + "field_exists": false, + "size": 8 + } + ] + } + }, + "cfi.pflash01": { + "Name": "cfi.pflash01", + "version_id": 1, + "minimum_version_id": 1 + }, + "megasas": { + "Name": "megasas", + "version_id": 0, + "minimum_version_id": 0, + "Description": { + "name": "megasas", + "version_id": 0, + "minimum_version_id": 0, + "Fields": [ + { + "field": "parent_obj", + "version_id": 0, + "field_exists": false, + "size": 1944, + "Description": { + "name": "PCIDevice", + "version_id": 2, + "minimum_version_id": 1, + "Fields": [ + { + "field": "version_id", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "config", + "version_id": 0, + "field_exists": false, + "size": 256 + } + ] + } + }, + { + "field": "fw_state", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "intr_mask", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "doorbell", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "reply_queue_pa", + "version_id": 0, + "field_exists": false, + "size": 8 + }, + { + "field": "consumer_pa", + "version_id": 0, + "field_exists": false, + "size": 8 + }, + { + "field": "producer_pa", + "version_id": 0, + "field_exists": false, + "size": 8 + } + ] + } + }, + "PIIX3-xen": { + "Name": "PIIX3-xen", + "version_id": 3, + "minimum_version_id": 2, + "Description": { + "name": "PIIX3", + "version_id": 3, + "minimum_version_id": 2, + "Fields": [ + { + "field": "dev", + "version_id": 0, + "field_exists": false, + "size": 1944, + "Description": { + "name": "PCIDevice", + "version_id": 2, + "minimum_version_id": 1, + "Fields": [ + { + "field": "version_id", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "config", + "version_id": 0, + "field_exists": false, + "size": 256 + }, + { + "field": "irq_state", + "version_id": 2, + "field_exists": false, + "size": 16 + } + ] + } + }, + { + "field": "pci_irq_levels_vmstate", + "version_id": 3, + "field_exists": false, + "size": 4 + } + ] + } + }, + "tpci200": { + "Name": "tpci200", + "version_id": 1, + "minimum_version_id": 1, + "Description": { + "name": "tpci2002", + "version_id": 1, + "minimum_version_id": 1, + "Fields": [ + { + "field": "dev", + "version_id": 0, + "field_exists": false, + "size": 1944, + "Description": { + "name": "PCIDevice", + "version_id": 2, + "minimum_version_id": 1, + "Fields": [ + { + "field": "version_id", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "config", + "version_id": 0, + "field_exists": false, + "size": 256 + }, + { + "field": "irq_state", + "version_id": 2, + "field_exists": false, + "size": 16 + } + ] + } + }, + { + "field": "big_endian", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "ctrl", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "status", + "version_id": 0, + "field_exists": false, + "size": 2 + }, + { + "field": "int_set", + "version_id": 0, + "field_exists": false, + "size": 1 + } + ] + } + }, + "SUNW,fdtwo": { + "Name": "SUNW,fdtwo", + "version_id": 2, + "minimum_version_id": 2, + "Description": { + "name": "fdc", + "version_id": 1, + "minimum_version_id": 2, + "Fields": [ + { + "field": "state", + "version_id": 0, + "field_exists": false, + "size": 360, + "Description": { + "name": "fdc", + "version_id": 2, + "minimum_version_id": 2, + "Fields": [ + { + "field": "sra", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "srb", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "dor_vmstate", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "tdr", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "dsr", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "msr", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "status0", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "status1", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "status2", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "fifo", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "data_pos", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "data_len", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "data_state", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "data_dir", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "eot", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "timer0", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "timer1", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "precomp_trk", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "config", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "lock", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "pwrd", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "num_floppies", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "drives", + "version_id": 1, + "field_exists": false, + "size": 40, + "Description": { + "name": "fdrive", + "version_id": 1, + "minimum_version_id": 1, + "Fields": [ + { + "field": "head", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "track", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "sect", + "version_id": 0, + "field_exists": false, + "size": 1 + } + ], + "Subsections": [ + { + "name": "fdrive/media_changed", + "version_id": 1, + "minimum_version_id": 1, + "Fields": [ + { + "field": "media_changed", + "version_id": 0, + "field_exists": false, + "size": 1 + } + ] + } + ] + } + } + ] + } + } + ] + } + }, + "usb-kbd": { + "Name": "usb-kbd", + "version_id": 1, + "minimum_version_id": 1, + "Description": { + "name": "usb-kbd", + "version_id": 1, + "minimum_version_id": 1, + "Fields": [ + { + "field": "dev", + "version_id": 0, + "field_exists": false, + "size": 5832, + "Description": { + "name": "USBDevice", + "version_id": 1, + "minimum_version_id": 1, + "Fields": [ + { + "field": "addr", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "state", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "remote_wakeup", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "setup_state", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "setup_len", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "setup_index", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "setup_buf", + "version_id": 0, + "field_exists": false, + "size": 1 + } + ] + } + }, + { + "field": "hid", + "version_id": 0, + "field_exists": false, + "size": 312, + "Description": { + "name": "HIDKeyboardDevice", + "version_id": 1, + "minimum_version_id": 1, + "Fields": [ + { + "field": "kbd.keycodes", + "version_id": 0, + "field_exists": false, + "size": 2 + }, + { + "field": "head", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "n", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "kbd.modifiers", + "version_id": 0, + "field_exists": false, + "size": 2 + }, + { + "field": "kbd.leds", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "kbd.key", + "version_id": 0, + "field_exists": false, + "size": 1 + }, + { + "field": "kbd.keys", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "protocol", + "version_id": 0, + "field_exists": false, + "size": 4 + }, + { + "field": "idle", + "version_id": 0, + "field_exists": false, + "size": 1 + } + ] + } + } + ] + } + } +} diff --git a/tests/wdt_ib700-test.c b/tests/wdt_ib700-test.c new file mode 100644 index 000000000..513a53385 --- /dev/null +++ b/tests/wdt_ib700-test.c @@ -0,0 +1,134 @@ +/* + * QTest testcase for the IB700 watchdog + * + * Copyright (c) 2014 Red Hat, Inc. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include <glib.h> +#include <string.h> +#include "libqtest.h" +#include "qemu/osdep.h" + +#define NS_PER_SEC 1000000000ULL + +static void qmp_check_no_event(void) +{ + QDict *resp = qmp("{'execute':'query-status'}"); + g_assert(qdict_haskey(resp, "return")); + QDECREF(resp); +} + +static QDict *qmp_get_event(const char *name) +{ + QDict *event = qmp(""); + QDict *data; + g_assert(qdict_haskey(event, "event")); + g_assert(!strcmp(qdict_get_str(event, "event"), name)); + + if (qdict_haskey(event, "data")) { + data = qdict_get_qdict(event, "data"); + QINCREF(data); + } else { + data = NULL; + } + + QDECREF(event); + return data; +} + +static QDict *ib700_program_and_wait(QTestState *s) +{ + clock_step(NS_PER_SEC * 40); + qmp_check_no_event(); + + /* 2 second limit */ + outb(0x443, 14); + + /* Ping */ + clock_step(NS_PER_SEC); + qmp_check_no_event(); + outb(0x443, 14); + + /* Disable */ + clock_step(NS_PER_SEC); + qmp_check_no_event(); + outb(0x441, 1); + clock_step(3 * NS_PER_SEC); + qmp_check_no_event(); + + /* Enable and let it fire */ + outb(0x443, 13); + clock_step(3 * NS_PER_SEC); + qmp_check_no_event(); + clock_step(2 * NS_PER_SEC); + return qmp_get_event("WATCHDOG"); +} + + +static void ib700_pause(void) +{ + QDict *d; + QTestState *s = qtest_start("-watchdog-action pause -device ib700"); + qtest_irq_intercept_in(s, "ioapic"); + d = ib700_program_and_wait(s); + g_assert(!strcmp(qdict_get_str(d, "action"), "pause")); + QDECREF(d); + d = qmp_get_event("STOP"); + QDECREF(d); + qtest_end(); +} + +static void ib700_reset(void) +{ + QDict *d; + QTestState *s = qtest_start("-watchdog-action reset -device ib700"); + qtest_irq_intercept_in(s, "ioapic"); + d = ib700_program_and_wait(s); + g_assert(!strcmp(qdict_get_str(d, "action"), "reset")); + QDECREF(d); + d = qmp_get_event("RESET"); + QDECREF(d); + qtest_end(); +} + +static void ib700_shutdown(void) +{ + QDict *d; + QTestState *s = qtest_start("-watchdog-action reset -no-reboot -device ib700"); + qtest_irq_intercept_in(s, "ioapic"); + d = ib700_program_and_wait(s); + g_assert(!strcmp(qdict_get_str(d, "action"), "reset")); + QDECREF(d); + d = qmp_get_event("SHUTDOWN"); + QDECREF(d); + qtest_end(); +} + +static void ib700_none(void) +{ + QDict *d; + QTestState *s = qtest_start("-watchdog-action none -device ib700"); + qtest_irq_intercept_in(s, "ioapic"); + d = ib700_program_and_wait(s); + g_assert(!strcmp(qdict_get_str(d, "action"), "none")); + QDECREF(d); + qtest_end(); +} + +int main(int argc, char **argv) +{ + int ret; + + g_test_init(&argc, &argv, NULL); + qtest_add_func("/wdt_ib700/pause", ib700_pause); + qtest_add_func("/wdt_ib700/reset", ib700_reset); + qtest_add_func("/wdt_ib700/shutdown", ib700_shutdown); + qtest_add_func("/wdt_ib700/none", ib700_none); + + ret = g_test_run(); + + return ret; +} |