diff options
Diffstat (limited to 'tests')
42 files changed, 2466 insertions, 196 deletions
diff --git a/tests/.gitignore b/tests/.gitignore index 72c18aaab0..f2bf85c8c4 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -5,6 +5,7 @@ benchmark-crypto-hmac check-* !check-*.c !check-*.sh +fp/*.out qht-bench rcutorture test-* diff --git a/tests/Makefile.include b/tests/Makefile.include index 3741f8f6dd..2187b0c5aa 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -70,6 +70,7 @@ check-unit-y += tests/test-throttle$(EXESUF) check-unit-y += tests/test-thread-pool$(EXESUF) check-unit-y += tests/test-hbitmap$(EXESUF) check-unit-y += tests/test-bdrv-drain$(EXESUF) +check-unit-y += tests/test-bdrv-graph-mod$(EXESUF) check-unit-y += tests/test-blockjob$(EXESUF) check-unit-y += tests/test-blockjob-txn$(EXESUF) check-unit-y += tests/test-block-backend$(EXESUF) @@ -114,7 +115,12 @@ ifneq (,$(findstring qemu-ga,$(TOOLS))) check-unit-$(land,$(CONFIG_LINUX),$(CONFIG_VIRTIO_SERIAL)) += tests/test-qga$(EXESUF) endif check-unit-y += tests/test-timed-average$(EXESUF) +check-unit-$(CONFIG_INOTIFY1) += tests/test-util-filemonitor$(EXESUF) check-unit-y += tests/test-util-sockets$(EXESUF) +check-unit-y += tests/test-authz-simple$(EXESUF) +check-unit-y += tests/test-authz-list$(EXESUF) +check-unit-y += tests/test-authz-listfile$(EXESUF) +check-unit-$(CONFIG_AUTH_PAM) += tests/test-authz-pam$(EXESUF) check-unit-y += tests/test-io-task$(EXESUF) check-unit-y += tests/test-io-channel-socket$(EXESUF) check-unit-y += tests/test-io-channel-file$(EXESUF) @@ -192,6 +198,7 @@ check-qtest-i386-$(CONFIG_ISA_IPMI_KCS) += tests/ipmi-kcs-test$(EXESUF) # check-qtest-i386-$(CONFIG_ISA_IPMI_BT) += tests/ipmi-bt-test$(EXESUF) check-qtest-i386-y += tests/i440fx-test$(EXESUF) check-qtest-i386-y += tests/fw_cfg-test$(EXESUF) +check-qtest-i386-y += tests/device-plug-test$(EXESUF) check-qtest-i386-y += tests/drive_del-test$(EXESUF) check-qtest-i386-$(CONFIG_WDT_IB700) += tests/wdt_ib700-test$(EXESUF) check-qtest-i386-y += tests/tco-test$(EXESUF) @@ -256,6 +263,7 @@ check-qtest-ppc-$(CONFIG_M48T59) += tests/m48t59-test$(EXESUF) check-qtest-ppc64-y += $(check-qtest-ppc-y) check-qtest-ppc64-$(CONFIG_PSERIES) += tests/spapr-phb-test$(EXESUF) +check-qtest-ppc64-$(CONFIG_PSERIES) += tests/device-plug-test$(EXESUF) check-qtest-ppc64-$(CONFIG_POWERNV) += tests/pnv-xscom-test$(EXESUF) check-qtest-ppc64-y += tests/migration-test$(EXESUF) check-qtest-ppc64-$(CONFIG_PSERIES) += tests/rtas-test$(EXESUF) @@ -310,6 +318,7 @@ check-qtest-s390x-$(CONFIG_SLIRP) += tests/test-netfilter$(EXESUF) check-qtest-s390x-$(CONFIG_POSIX) += tests/test-filter-mirror$(EXESUF) check-qtest-s390x-$(CONFIG_POSIX) += tests/test-filter-redirector$(EXESUF) check-qtest-s390x-y += tests/drive_del-test$(EXESUF) +check-qtest-s390x-y += tests/device-plug-test$(EXESUF) check-qtest-s390x-y += tests/virtio-ccw-test$(EXESUF) check-qtest-s390x-y += tests/cpu-plug-test$(EXESUF) check-qtest-s390x-y += tests/migration-test$(EXESUF) @@ -532,9 +541,10 @@ test-qom-obj-y = $(qom-obj-y) $(test-util-obj-y) test-qapi-obj-y = tests/test-qapi-visit.o tests/test-qapi-types.o \ tests/test-qapi-introspect.o \ $(test-qom-obj-y) -benchmark-crypto-obj-y = $(crypto-obj-y) $(test-qom-obj-y) -test-crypto-obj-y = $(crypto-obj-y) $(test-qom-obj-y) +benchmark-crypto-obj-y = $(authz-obj-y) $(crypto-obj-y) $(test-qom-obj-y) +test-crypto-obj-y = $(authz-obj-y) $(crypto-obj-y) $(test-qom-obj-y) test-io-obj-y = $(io-obj-y) $(test-crypto-obj-y) +test-authz-obj-y = $(test-qom-obj-y) $(authz-obj-y) test-block-obj-y = $(block-obj-y) $(test-io-obj-y) tests/iothread.o tests/check-qnum$(EXESUF): tests/check-qnum.o $(test-util-obj-y) @@ -555,6 +565,7 @@ tests/test-aio$(EXESUF): tests/test-aio.o $(test-block-obj-y) tests/test-aio-multithread$(EXESUF): tests/test-aio-multithread.o $(test-block-obj-y) tests/test-throttle$(EXESUF): tests/test-throttle.o $(test-block-obj-y) tests/test-bdrv-drain$(EXESUF): tests/test-bdrv-drain.o $(test-block-obj-y) $(test-util-obj-y) +tests/test-bdrv-graph-mod$(EXESUF): tests/test-bdrv-graph-mod.o $(test-block-obj-y) $(test-util-obj-y) tests/test-blockjob$(EXESUF): tests/test-blockjob.o $(test-block-obj-y) $(test-util-obj-y) tests/test-blockjob-txn$(EXESUF): tests/test-blockjob-txn.o $(test-block-obj-y) $(test-util-obj-y) tests/test-block-backend$(EXESUF): tests/test-block-backend.o $(test-block-obj-y) $(test-util-obj-y) @@ -657,8 +668,14 @@ tests/test-crypto-tlssession$(EXESUF): tests/test-crypto-tlssession.o \ tests/crypto-tls-x509-helpers.o tests/pkix_asn1_tab.o \ tests/crypto-tls-psk-helpers.o \ $(test-crypto-obj-y) +tests/test-util-filemonitor$(EXESUF): tests/test-util-filemonitor.o \ + $(test-util-obj-y) tests/test-util-sockets$(EXESUF): tests/test-util-sockets.o \ tests/socket-helpers.o $(test-util-obj-y) +tests/test-authz-simple$(EXESUF): tests/test-authz-simple.o $(test-authz-obj-y) +tests/test-authz-list$(EXESUF): tests/test-authz-list.o $(test-authz-obj-y) +tests/test-authz-listfile$(EXESUF): tests/test-authz-listfile.o $(test-authz-obj-y) +tests/test-authz-pam$(EXESUF): tests/test-authz-pam.o $(test-authz-obj-y) tests/test-io-task$(EXESUF): tests/test-io-task.o $(test-io-obj-y) tests/test-io-channel-socket$(EXESUF): tests/test-io-channel-socket.o \ tests/io-channel-helpers.o tests/socket-helpers.o $(test-io-obj-y) @@ -750,6 +767,7 @@ tests/ipoctal232-test$(EXESUF): tests/ipoctal232-test.o tests/qom-test$(EXESUF): tests/qom-test.o tests/test-hmp$(EXESUF): tests/test-hmp.o tests/machine-none-test$(EXESUF): tests/machine-none-test.o +tests/device-plug-test$(EXESUF): tests/device-plug-test.o tests/drive_del-test$(EXESUF): tests/drive_del-test.o $(libqos-virtio-obj-y) tests/nvme-test$(EXESUF): tests/nvme-test.o $(libqos-pc-obj-y) tests/pvpanic-test$(EXESUF): tests/pvpanic-test.o @@ -898,19 +916,18 @@ $(FP_TEST_BIN): # The full test suite can take a bit of time, default to a quick run # "-l 2 -r all" can take more than a day for some operations and is best # run manually -FP_TL=-l 1 +FP_TL=-l 1 -r all -# $1 = tests, $2 = description +# $1 = tests, $2 = description, $3 = test flags test-softfloat = $(call quiet-command, \ cd $(BUILD_DIR)/tests/fp && \ - ./fp-test -s $(FP_TL) $1 > $2.out 2>&1 || \ + ./fp-test -s $(if $3,$3,$(FP_TL)) $1 > $2.out 2>&1 || \ (cat $2.out && exit 1;), \ "FLOAT TEST", $2) # Conversion Routines: # FIXME: i32_to_extF80 (broken), i64_to_extF80 (broken) -# ui32_to_f128 (not implemented), f128_to_ui32 (not implemented) -# extF80_roundToInt (broken) +# ui32_to_f128 (not implemented), extF80_roundToInt (broken) # check-softfloat-conv: $(FP_TEST_BIN) $(call test-softfloat, \ @@ -939,9 +956,11 @@ check-softfloat-conv: $(FP_TEST_BIN) f16_to_ui32 f16_to_ui32_r_minMag \ f32_to_ui32 f32_to_ui32_r_minMag \ f64_to_ui32 f64_to_ui32_r_minMag \ + f128_to_ui32 f128_to_ui32_r_minMag \ f16_to_ui64 f16_to_ui64_r_minMag \ f32_to_ui64 f32_to_ui64_r_minMag \ - f64_to_ui64 f64_to_ui64_r_minMag, \ + f64_to_ui64 f64_to_ui64_r_minMag \ + f128_to_ui64 f128_to_ui64_r_minMag, \ float-to-uint) $(call test-softfloat, \ f16_roundToInt f32_roundToInt \ @@ -983,7 +1002,7 @@ check-softfloat-compare: $(SF_COMPARE_RULES) check-softfloat-mulAdd: $(FP_TEST_BIN) $(call test-softfloat, \ f16_mulAdd f32_mulAdd f64_mulAdd f128_mulAdd, \ - mulAdd) + mulAdd,-l 1) # FIXME: extF80_rem (broken) check-softfloat-rem: $(FP_TEST_BIN) diff --git a/tests/device-plug-test.c b/tests/device-plug-test.c new file mode 100644 index 0000000000..318e422d51 --- /dev/null +++ b/tests/device-plug-test.c @@ -0,0 +1,178 @@ +/* + * QEMU device plug/unplug handling + * + * Copyright (C) 2019 Red Hat Inc. + * + * Authors: + * David Hildenbrand <david@redhat.com> + * + * 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 "qemu/osdep.h" +#include "libqtest.h" +#include "qapi/qmp/qdict.h" +#include "qapi/qmp/qstring.h" + +static void device_del_start(QTestState *qtest, const char *id) +{ + qtest_qmp_send(qtest, + "{'execute': 'device_del', 'arguments': { 'id': %s } }", id); +} + +static void device_del_finish(QTestState *qtest) +{ + QDict *resp = qtest_qmp_receive(qtest); + + g_assert(qdict_haskey(resp, "return")); + qobject_unref(resp); +} + +static void device_del_request(QTestState *qtest, const char *id) +{ + device_del_start(qtest, id); + device_del_finish(qtest); +} + +static void system_reset(QTestState *qtest) +{ + QDict *resp; + + resp = qtest_qmp(qtest, "{'execute': 'system_reset'}"); + g_assert(qdict_haskey(resp, "return")); + qobject_unref(resp); +} + +static void wait_device_deleted_event(QTestState *qtest, const char *id) +{ + QDict *resp, *data; + QString *qstr; + + /* + * Other devices might get removed along with the removed device. Skip + * these. The device of interest will be the last one. + */ + for (;;) { + resp = qtest_qmp_eventwait_ref(qtest, "DEVICE_DELETED"); + data = qdict_get_qdict(resp, "data"); + if (!data || !qdict_get(data, "device")) { + qobject_unref(resp); + continue; + } + qstr = qobject_to(QString, qdict_get(data, "device")); + g_assert(qstr); + if (!strcmp(qstring_get_str(qstr), id)) { + qobject_unref(resp); + break; + } + qobject_unref(resp); + } +} + +static void test_pci_unplug_request(void) +{ + QTestState *qtest = qtest_initf("-device virtio-mouse-pci,id=dev0"); + + /* + * Request device removal. As the guest is not running, the request won't + * be processed. However during system reset, the removal will be + * handled, removing the device. + */ + device_del_request(qtest, "dev0"); + system_reset(qtest); + wait_device_deleted_event(qtest, "dev0"); + + qtest_quit(qtest); +} + +static void test_ccw_unplug(void) +{ + QTestState *qtest = qtest_initf("-device virtio-balloon-ccw,id=dev0"); + + /* + * The DEVICE_DELETED events will be sent before the command + * completes. + */ + device_del_start(qtest, "dev0"); + wait_device_deleted_event(qtest, "dev0"); + device_del_finish(qtest); + + qtest_quit(qtest); +} + +static void test_spapr_cpu_unplug_request(void) +{ + QTestState *qtest; + + qtest = qtest_initf("-cpu power9_v2.0 -smp 1,maxcpus=2 " + "-device power9_v2.0-spapr-cpu-core,core-id=1,id=dev0"); + + /* similar to test_pci_unplug_request */ + device_del_request(qtest, "dev0"); + system_reset(qtest); + wait_device_deleted_event(qtest, "dev0"); + + qtest_quit(qtest); +} + +static void test_spapr_memory_unplug_request(void) +{ + QTestState *qtest; + + qtest = qtest_initf("-m 256M,slots=1,maxmem=768M " + "-object memory-backend-ram,id=mem0,size=512M " + "-device pc-dimm,id=dev0,memdev=mem0"); + + /* similar to test_pci_unplug_request */ + device_del_request(qtest, "dev0"); + system_reset(qtest); + wait_device_deleted_event(qtest, "dev0"); + + qtest_quit(qtest); +} + +static void test_spapr_phb_unplug_request(void) +{ + QTestState *qtest; + + qtest = qtest_initf("-device spapr-pci-host-bridge,index=1,id=dev0"); + + /* similar to test_pci_unplug_request */ + device_del_request(qtest, "dev0"); + system_reset(qtest); + wait_device_deleted_event(qtest, "dev0"); + + qtest_quit(qtest); +} + +int main(int argc, char **argv) +{ + const char *arch = qtest_get_arch(); + + g_test_init(&argc, &argv, NULL); + + /* + * We need a system that will process unplug requests during system resets + * and does not do PCI surprise removal. This holds for x86 ACPI, + * s390x and spapr. + */ + qtest_add_func("/device-plug/pci-unplug-request", + test_pci_unplug_request); + + if (!strcmp(arch, "s390x")) { + qtest_add_func("/device-plug/ccw-unplug", + test_ccw_unplug); + } + + if (!strcmp(arch, "ppc64")) { + qtest_add_func("/device-plug/spapr-cpu-unplug-request", + test_spapr_cpu_unplug_request); + qtest_add_func("/device-plug/spapr-memory-unplug-request", + test_spapr_memory_unplug_request); + qtest_add_func("/device-plug/spapr-phb-unplug-request", + test_spapr_phb_unplug_request); + } + + return g_test_run(); +} diff --git a/tests/fp/fp-test.c b/tests/fp/fp-test.c index 2a35ef601d..7d0faf2b47 100644 --- a/tests/fp/fp-test.c +++ b/tests/fp/fp-test.c @@ -125,17 +125,42 @@ static void not_implemented(void) static bool blacklisted(unsigned op, int rmode) { - /* odd has only been implemented for a few 128-bit ops */ + /* odd has not been implemented for any 80-bit ops */ if (rmode == softfloat_round_odd) { switch (op) { - case F128_ADD: - case F128_SUB: - case F128_MUL: - case F128_DIV: - case F128_TO_F64: - case F128_SQRT: - return false; - default: + case EXTF80_TO_UI32: + case EXTF80_TO_UI64: + case EXTF80_TO_I32: + case EXTF80_TO_I64: + case EXTF80_TO_UI32_R_MINMAG: + case EXTF80_TO_UI64_R_MINMAG: + case EXTF80_TO_I32_R_MINMAG: + case EXTF80_TO_I64_R_MINMAG: + case EXTF80_TO_F16: + case EXTF80_TO_F32: + case EXTF80_TO_F64: + case EXTF80_TO_F128: + case EXTF80_ROUNDTOINT: + case EXTF80_ADD: + case EXTF80_SUB: + case EXTF80_MUL: + case EXTF80_DIV: + case EXTF80_REM: + case EXTF80_SQRT: + case EXTF80_EQ: + case EXTF80_LE: + case EXTF80_LT: + case EXTF80_EQ_SIGNALING: + case EXTF80_LE_QUIET: + case EXTF80_LT_QUIET: + case UI32_TO_EXTF80: + case UI64_TO_EXTF80: + case I32_TO_EXTF80: + case I64_TO_EXTF80: + case F16_TO_EXTF80: + case F32_TO_EXTF80: + case F64_TO_EXTF80: + case F128_TO_EXTF80: return true; } } @@ -622,7 +647,8 @@ static void do_testfloat(int op, int rmode, bool exact) test_ab_extF80_z_bool(true_ab_extF80M_z_bool, subj_ab_extF80M_z_bool); break; case F128_TO_UI32: - not_implemented(); + test_a_f128_z_ui32_rx(slow_f128M_to_ui32, qemu_f128M_to_ui32, rmode, + exact); break; case F128_TO_UI64: test_a_f128_z_ui64_rx(slow_f128M_to_ui64, qemu_f128M_to_ui64, rmode, diff --git a/tests/fp/wrap.inc.c b/tests/fp/wrap.inc.c index d3bf600cd0..0cbd20013e 100644 --- a/tests/fp/wrap.inc.c +++ b/tests/fp/wrap.inc.c @@ -367,6 +367,7 @@ WRAP_80_TO_INT_MINMAG(qemu_extF80M_to_i64_r_minMag, WRAP_128_TO_INT(qemu_f128M_to_i32, float128_to_int32, int_fast32_t) WRAP_128_TO_INT(qemu_f128M_to_i64, float128_to_int64, int_fast64_t) +WRAP_128_TO_INT(qemu_f128M_to_ui32, float128_to_uint32, uint_fast32_t) WRAP_128_TO_INT(qemu_f128M_to_ui64, float128_to_uint64, uint_fast64_t) #undef WRAP_128_TO_INT diff --git a/tests/qemu-iotests/045 b/tests/qemu-iotests/045 index 55a5d31ca8..d5484a0ee1 100755 --- a/tests/qemu-iotests/045 +++ b/tests/qemu-iotests/045 @@ -132,7 +132,7 @@ class TestSCMFd(iotests.QMPTestCase): qemu_img('create', '-f', iotests.imgfmt, image0, '128K') # Add an unused monitor, to verify it works fine when two monitor # instances present - self.vm.add_monitor_telnet("0",4445) + self.vm.add_monitor_null() self.vm.launch() def tearDown(self): diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out index 793af2ab96..b900935fbc 100644 --- a/tests/qemu-iotests/051.out +++ b/tests/qemu-iotests/051.out @@ -82,7 +82,7 @@ QEMU X.Y.Z monitor - type 'help' for more information Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,backing.file.filename=TEST_DIR/t.qcow2.orig,if=none,id=drive0 -nodefaults QEMU X.Y.Z monitor - type 'help' for more information (qemu) info block -drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) +drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2.orig"}}, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}} (qcow2) Removable device: not locked, tray closed Cache mode: writeback Backing file: TEST_DIR/t.qcow2.orig (chain depth: 1) @@ -172,7 +172,7 @@ QEMU_PROG: -drive driver=null-co,cache=invalid_value: invalid cache option Testing: -drive file=TEST_DIR/t.qcow2,cache=writeback,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults QEMU X.Y.Z monitor - type 'help' for more information (qemu) info block -drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) +drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2.base"}}, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}} (qcow2) Removable device: not locked, tray closed Cache mode: writeback Backing file: TEST_DIR/t.qcow2.base (chain depth: 1) @@ -192,7 +192,7 @@ backing-file: TEST_DIR/t.qcow2.base (file, read-only) Testing: -drive file=TEST_DIR/t.qcow2,cache=writethrough,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults QEMU X.Y.Z monitor - type 'help' for more information (qemu) info block -drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) +drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2.base"}}, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}} (qcow2) Removable device: not locked, tray closed Cache mode: writethrough Backing file: TEST_DIR/t.qcow2.base (chain depth: 1) @@ -212,7 +212,7 @@ backing-file: TEST_DIR/t.qcow2.base (file, read-only) Testing: -drive file=TEST_DIR/t.qcow2,cache=unsafe,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults QEMU X.Y.Z monitor - type 'help' for more information (qemu) info block -drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) +drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2.base"}}, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}} (qcow2) Removable device: not locked, tray closed Cache mode: writeback, ignore flushes Backing file: TEST_DIR/t.qcow2.base (chain depth: 1) diff --git a/tests/qemu-iotests/051.pc.out b/tests/qemu-iotests/051.pc.out index ca64edae6a..8c5c735dfd 100644 --- a/tests/qemu-iotests/051.pc.out +++ b/tests/qemu-iotests/051.pc.out @@ -82,7 +82,7 @@ QEMU X.Y.Z monitor - type 'help' for more information Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,backing.file.filename=TEST_DIR/t.qcow2.orig,if=none,id=drive0 -nodefaults QEMU X.Y.Z monitor - type 'help' for more information (qemu) info block -drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) +drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2.orig"}}, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}} (qcow2) Removable device: not locked, tray closed Cache mode: writeback Backing file: TEST_DIR/t.qcow2.orig (chain depth: 1) @@ -244,7 +244,7 @@ QEMU_PROG: -drive driver=null-co,cache=invalid_value: invalid cache option Testing: -drive file=TEST_DIR/t.qcow2,cache=writeback,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults QEMU X.Y.Z monitor - type 'help' for more information (qemu) info block -drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) +drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2.base"}}, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}} (qcow2) Removable device: not locked, tray closed Cache mode: writeback Backing file: TEST_DIR/t.qcow2.base (chain depth: 1) @@ -264,7 +264,7 @@ backing-file: TEST_DIR/t.qcow2.base (file, read-only) Testing: -drive file=TEST_DIR/t.qcow2,cache=writethrough,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults QEMU X.Y.Z monitor - type 'help' for more information (qemu) info block -drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) +drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2.base"}}, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}} (qcow2) Removable device: not locked, tray closed Cache mode: writethrough Backing file: TEST_DIR/t.qcow2.base (chain depth: 1) @@ -284,7 +284,7 @@ backing-file: TEST_DIR/t.qcow2.base (file, read-only) Testing: -drive file=TEST_DIR/t.qcow2,cache=unsafe,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults QEMU X.Y.Z monitor - type 'help' for more information (qemu) info block -drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) +drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2.base"}}, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}} (qcow2) Removable device: not locked, tray closed Cache mode: writeback, ignore flushes Backing file: TEST_DIR/t.qcow2.base (chain depth: 1) diff --git a/tests/qemu-iotests/110 b/tests/qemu-iotests/110 index b64b3b215a..185ad5437e 100755 --- a/tests/qemu-iotests/110 +++ b/tests/qemu-iotests/110 @@ -29,6 +29,7 @@ status=1 # failure is the default! _cleanup() { _cleanup_test_img + rm -f "$TEST_IMG.copy" } trap "_cleanup; exit \$status" 0 1 2 3 15 @@ -60,7 +61,8 @@ echo '=== Non-reconstructable filename ===' echo # Across blkdebug without a config file, you cannot reconstruct filenames, so -# qemu is incapable of knowing the directory of the top image +# qemu is incapable of knowing the directory of the top image from the filename +# alone. However, using bdrv_dirname(), it should still work. TEST_IMG="json:{ 'driver': '$IMGFMT', 'file': { @@ -85,6 +87,31 @@ echo # omit the image size; it should work anyway _make_test_img -b "$TEST_IMG_REL.base" +echo +echo '=== Nodes without a common directory ===' +echo + +cp "$TEST_IMG" "$TEST_IMG.copy" + +# Should inform us that the actual path of the backing file cannot be determined +TEST_IMG="json:{ + 'driver': '$IMGFMT', + 'file': { + 'driver': 'quorum', + 'vote-threshold': 1, + 'children': [ + { + 'driver': 'file', + 'filename': '$TEST_IMG' + }, + { + 'driver': 'file', + 'filename': '$TEST_IMG.copy' + } + ] + } +}" _img_info | _filter_img_info + # success, all done echo '*** done' diff --git a/tests/qemu-iotests/110.out b/tests/qemu-iotests/110.out index b3584ff87f..46e6a60510 100644 --- a/tests/qemu-iotests/110.out +++ b/tests/qemu-iotests/110.out @@ -14,9 +14,16 @@ backing file: t.IMGFMT.base (actual path: TEST_DIR/t.IMGFMT.base) image: json:{"driver": "IMGFMT", "file": {"set-state.0.event": "read_aio", "image": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "driver": "blkdebug", "set-state.0.new_state": 42}} file format: IMGFMT virtual size: 64M (67108864 bytes) -backing file: t.IMGFMT.base (cannot determine actual path) +backing file: t.IMGFMT.base (actual path: TEST_DIR/t.IMGFMT.base) === Backing name is always relative to the backed image === Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=t.IMGFMT.base + +=== Nodes without a common directory === + +image: json:{"driver": "IMGFMT", "file": {"children": [{"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, {"driver": "file", "filename": "TEST_DIR/t.IMGFMT.copy"}], "driver": "quorum", "vote-threshold": 1}} +file format: IMGFMT +virtual size: 64M (67108864 bytes) +backing file: t.IMGFMT.base (cannot determine actual path) *** done diff --git a/tests/qemu-iotests/178 b/tests/qemu-iotests/178 index 3f4b4a4564..927bf06e4d 100755 --- a/tests/qemu-iotests/178 +++ b/tests/qemu-iotests/178 @@ -142,6 +142,14 @@ for ofmt in human json; do # The backing file doesn't need to exist :) $QEMU_IMG measure --output=$ofmt -o backing_file=x \ -f "$fmt" -O "$IMGFMT" "$TEST_IMG" + + echo + echo "== $fmt input image and LUKS encryption ==" + echo + $QEMU_IMG measure --output=$ofmt \ + --object secret,id=sec0,data=base \ + -o encrypt.format=luks,encrypt.key-secret=sec0,encrypt.iter-time=10 \ + -f "$fmt" -O "$IMGFMT" "$TEST_IMG" fi echo diff --git a/tests/qemu-iotests/178.out.qcow2 b/tests/qemu-iotests/178.out.qcow2 index d42d4a4597..55a8dc926f 100644 --- a/tests/qemu-iotests/178.out.qcow2 +++ b/tests/qemu-iotests/178.out.qcow2 @@ -68,6 +68,11 @@ converted image file size in bytes: 458752 required size: 1074135040 fully allocated size: 1074135040 +== qcow2 input image and LUKS encryption == + +required size: 2686976 +fully allocated size: 1076232192 + == qcow2 input image and preallocation (human) == required size: 1074135040 @@ -114,6 +119,11 @@ converted image file size in bytes: 524288 required size: 1074135040 fully allocated size: 1074135040 +== raw input image and LUKS encryption == + +required size: 2686976 +fully allocated size: 1076232192 + == raw input image and preallocation (human) == required size: 1074135040 @@ -205,6 +215,13 @@ converted image file size in bytes: 458752 "fully-allocated": 1074135040 } +== qcow2 input image and LUKS encryption == + +{ + "required": 2686976, + "fully-allocated": 1076232192 +} + == qcow2 input image and preallocation (json) == { @@ -263,6 +280,13 @@ converted image file size in bytes: 524288 "fully-allocated": 1074135040 } +== raw input image and LUKS encryption == + +{ + "required": 2686976, + "fully-allocated": 1076232192 +} + == raw input image and preallocation (json) == { diff --git a/tests/qemu-iotests/206.out b/tests/qemu-iotests/206.out index 91f4db55d3..0f1c23babb 100644 --- a/tests/qemu-iotests/206.out +++ b/tests/qemu-iotests/206.out @@ -1,13 +1,13 @@ === Successful image creation (defaults) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "node_name": "imgfile"}} +{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "node-name": "imgfile"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "imgfile", "size": 134217728}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "imgfile", "size": 134217728}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -24,12 +24,12 @@ Format specific information: === Successful image creation (inline blockdev-add, explicit defaults) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "nocow": false, "preallocation": "off", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "nocow": false, "preallocation": "off", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 65536, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "lazy-refcounts": false, "preallocation": "off", "refcount-bits": 16, "size": 67108864, "version": "v3"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 65536, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "lazy-refcounts": false, "preallocation": "off", "refcount-bits": 16, "size": 67108864, "version": "v3"}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -46,12 +46,12 @@ Format specific information: === Successful image creation (v3 non-default options) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "nocow": true, "preallocation": "falloc", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "nocow": true, "preallocation": "falloc", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 2097152, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "lazy-refcounts": true, "preallocation": "metadata", "refcount-bits": 1, "size": 33554432, "version": "v3"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 2097152, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "lazy-refcounts": true, "preallocation": "metadata", "refcount-bits": 1, "size": 33554432, "version": "v3"}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -68,12 +68,12 @@ Format specific information: === Successful image creation (v2 non-default options) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"backing-file": "TEST_DIR/PID-t.qcow2.base", "backing-fmt": "qcow2", "cluster-size": 512, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "size": 33554432, "version": "v2"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"backing-file": "TEST_DIR/PID-t.qcow2.base", "backing-fmt": "qcow2", "cluster-size": 512, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "size": 33554432, "version": "v2"}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -90,7 +90,7 @@ Format specific information: === Successful image creation (encrypted) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "encrypt": {"cipher-alg": "twofish-128", "cipher-mode": "ctr", "format": "luks", "hash-alg": "sha1", "iter-time": 10, "ivgen-alg": "plain64", "ivgen-hash-alg": "md5", "key-secret": "keysec0"}, "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "size": 33554432}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "encrypt": {"cipher-alg": "twofish-128", "cipher-mode": "ctr", "format": "luks", "hash-alg": "sha1", "iter-time": 10, "ivgen-alg": "plain64", "ivgen-hash-alg": "md5", "key-secret": "keysec0"}, "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "size": 33554432}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -144,111 +144,111 @@ Format specific information: === Invalid BlockdevRef === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "this doesn't exist", "size": 33554432}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "this doesn't exist", "size": 33554432}}} {"return": {}} Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} === Invalid sizes === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 1234}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 1234}}} {"return": {}} Job failed: Image size must be a multiple of 512 bytes {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 18446744073709551104}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 18446744073709551104}}} {"return": {}} Job failed: Could not resize image: Image size cannot be negative {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 9223372036854775808}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 9223372036854775808}}} {"return": {}} Job failed: Could not resize image: Image size cannot be negative {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 9223372036854775296}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 9223372036854775296}}} {"return": {}} Job failed: Could not resize image: Failed to grow the L1 table: File too large {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} === Invalid version === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 67108864, "version": "v1"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 67108864, "version": "v1"}}} {"error": {"class": "GenericError", "desc": "Invalid parameter 'v1'"}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "lazy-refcounts": true, "size": 67108864, "version": "v2"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "lazy-refcounts": true, "size": 67108864, "version": "v2"}}} {"return": {}} Job failed: Lazy refcounts only supported with compatibility level 1.1 and above (use version=v3 or greater) {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "refcount-bits": 8, "size": 67108864, "version": "v2"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "refcount-bits": 8, "size": 67108864, "version": "v2"}}} {"return": {}} Job failed: Different refcount widths than 16 bits require compatibility level 1.1 or above (use version=v3 or greater) {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} === Invalid backing file options === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"backing-file": "/dev/null", "driver": "qcow2", "file": "node0", "preallocation": "full", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"backing-file": "/dev/null", "driver": "qcow2", "file": "node0", "preallocation": "full", "size": 67108864}}} {"return": {}} Job failed: Backing file and preallocation cannot be used at the same time {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"backing-fmt": "qcow2", "driver": "qcow2", "file": "node0", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"backing-fmt": "qcow2", "driver": "qcow2", "file": "node0", "size": 67108864}}} {"return": {}} Job failed: Backing format cannot be used without backing file {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} === Invalid cluster size === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 1234, "driver": "qcow2", "file": "node0", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 1234, "driver": "qcow2", "file": "node0", "size": 67108864}}} {"return": {}} Job failed: Cluster size must be a power of two between 512 and 2048k {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 128, "driver": "qcow2", "file": "node0", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 128, "driver": "qcow2", "file": "node0", "size": 67108864}}} {"return": {}} Job failed: Cluster size must be a power of two between 512 and 2048k {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 4194304, "driver": "qcow2", "file": "node0", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 4194304, "driver": "qcow2", "file": "node0", "size": 67108864}}} {"return": {}} Job failed: Cluster size must be a power of two between 512 and 2048k {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 0, "driver": "qcow2", "file": "node0", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 0, "driver": "qcow2", "file": "node0", "size": 67108864}}} {"return": {}} Job failed: Cluster size must be a power of two between 512 and 2048k {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 512, "driver": "qcow2", "file": "node0", "size": 281474976710656}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 512, "driver": "qcow2", "file": "node0", "size": 281474976710656}}} {"return": {}} Job failed: Could not resize image: Failed to grow the L1 table: File too large {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} === Invalid refcount width === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "refcount-bits": 128, "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "refcount-bits": 128, "size": 67108864}}} {"return": {}} Job failed: Refcount width must be a power of two and may not exceed 64 bits {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "refcount-bits": 0, "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "refcount-bits": 0, "size": 67108864}}} {"return": {}} Job failed: Refcount width must be a power of two and may not exceed 64 bits {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "refcount-bits": 7, "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "refcount-bits": 7, "size": 67108864}}} {"return": {}} Job failed: Refcount width must be a power of two and may not exceed 64 bits {"execute": "job-dismiss", "arguments": {"id": "job0"}} diff --git a/tests/qemu-iotests/207 b/tests/qemu-iotests/207 index c617ee7453..dfd3c51bd1 100755 --- a/tests/qemu-iotests/207 +++ b/tests/qemu-iotests/207 @@ -27,12 +27,16 @@ import re iotests.verify_image_format(supported_fmts=['raw']) iotests.verify_protocol(supported=['ssh']) -def filter_hash(msg): - return re.sub('"hash": "[0-9a-f]+"', '"hash": HASH', msg) +def filter_hash(qmsg): + def _filter(key, value): + if key == 'hash' and re.match('[0-9a-f]+', value): + return 'HASH' + return value + return iotests.filter_qmp(qmsg, _filter) def blockdev_create(vm, options): result = vm.qmp_log('blockdev-create', job_id='job0', options=options, - filters=[iotests.filter_testfiles, filter_hash]) + filters=[iotests.filter_qmp_testfiles, filter_hash]) if 'return' in result: assert result['return'] == {} diff --git a/tests/qemu-iotests/207.out b/tests/qemu-iotests/207.out index 45ac7c2a8f..568e8619d0 100644 --- a/tests/qemu-iotests/207.out +++ b/tests/qemu-iotests/207.out @@ -1,6 +1,6 @@ === Successful image creation (defaults) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -16,7 +16,7 @@ virtual size: 4.0M (4194304 bytes) === Test host-key-check options === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "none"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 8388608}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "none"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 8388608}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -25,7 +25,7 @@ image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.po file format: IMGFMT virtual size: 8.0M (8388608 bytes) -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "known_hosts"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "known_hosts"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -34,13 +34,13 @@ image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.po file format: IMGFMT virtual size: 4.0M (4194304 bytes) -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": "wrong", "mode": "hash", "type": "md5"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 2097152}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": "wrong", "mode": "hash", "type": "md5"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 2097152}}} {"return": {}} Job failed: remote host key does not match host_key_check 'wrong' {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": HASH, "mode": "hash", "type": "md5"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 8388608}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": "HASH", "mode": "hash", "type": "md5"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 8388608}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -49,13 +49,13 @@ image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.po file format: IMGFMT virtual size: 8.0M (8388608 bytes) -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": "wrong", "mode": "hash", "type": "sha1"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 2097152}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": "wrong", "mode": "hash", "type": "sha1"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 2097152}}} {"return": {}} Job failed: remote host key does not match host_key_check 'wrong' {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": HASH, "mode": "hash", "type": "sha1"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": "HASH", "mode": "hash", "type": "sha1"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -66,13 +66,13 @@ virtual size: 4.0M (4194304 bytes) === Invalid path and user === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "none"}, "path": "/this/is/not/an/existing/path", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "none"}, "path": "/this/is/not/an/existing/path", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}} {"return": {}} Job failed: failed to open remote file '/this/is/not/an/existing/path': Failed opening remote file (libssh2 error code: -31) {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "none"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}, "user": "invalid user"}, "size": 4194304}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "none"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}, "user": "invalid user"}, "size": 4194304}}} {"return": {}} Job failed: failed to authenticate using publickey authentication and the identities held by your ssh-agent {"execute": "job-dismiss", "arguments": {"id": "job0"}} diff --git a/tests/qemu-iotests/210 b/tests/qemu-iotests/210 index d142841e2b..565e3b7b9b 100755 --- a/tests/qemu-iotests/210 +++ b/tests/qemu-iotests/210 @@ -27,7 +27,8 @@ iotests.verify_image_format(supported_fmts=['luks']) iotests.verify_protocol(supported=['file']) def blockdev_create(vm, options): - result = vm.qmp_log('blockdev-create', job_id='job0', options=options) + result = vm.qmp_log('blockdev-create', job_id='job0', options=options, + filters=[iotests.filter_qmp_testfiles]) if 'return' in result: assert result['return'] == {} @@ -53,7 +54,7 @@ with iotests.FilePath('t.luks') as disk_path, \ 'size': 0 }) vm.qmp_log('blockdev-add', driver='file', filename=disk_path, - node_name='imgfile') + node_name='imgfile', filters=[iotests.filter_qmp_testfiles]) blockdev_create(vm, { 'driver': imgfmt, 'file': 'imgfile', diff --git a/tests/qemu-iotests/210.out b/tests/qemu-iotests/210.out index 923cb05117..a3692ce00d 100644 --- a/tests/qemu-iotests/210.out +++ b/tests/qemu-iotests/210.out @@ -1,13 +1,13 @@ === Successful image creation (defaults) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.luks", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.luks", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.luks", "node_name": "imgfile"}} +{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.luks", "node-name": "imgfile"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "luks", "file": "imgfile", "iter-time": 10, "key-secret": "keysec0", "size": 134217728}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "luks", "file": "imgfile", "iter-time": 10, "key-secret": "keysec0", "size": 134217728}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -54,12 +54,12 @@ Format specific information: === Successful image creation (with non-default options) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.luks", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.luks", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cipher-alg": "twofish-128", "cipher-mode": "ctr", "driver": "luks", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.luks"}, "hash-alg": "sha1", "iter-time": 10, "ivgen-alg": "plain64", "ivgen-hash-alg": "md5", "key-secret": "keysec0", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cipher-alg": "twofish-128", "cipher-mode": "ctr", "driver": "luks", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.luks"}, "hash-alg": "sha1", "iter-time": 10, "ivgen-alg": "plain64", "ivgen-hash-alg": "md5", "key-secret": "keysec0", "size": 67108864}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -106,7 +106,7 @@ Format specific information: === Invalid BlockdevRef === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "luks", "file": "this doesn't exist", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "luks", "file": "this doesn't exist", "size": 67108864}}} {"return": {}} Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist {"execute": "job-dismiss", "arguments": {"id": "job0"}} @@ -114,7 +114,7 @@ Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exi === Zero size === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "luks", "file": "node0", "iter-time": 10, "key-secret": "keysec0", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "luks", "file": "node0", "iter-time": 10, "key-secret": "keysec0", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -161,19 +161,19 @@ Format specific information: === Invalid sizes === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "luks", "file": "node0", "key-secret": "keysec0", "size": 18446744073709551104}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "luks", "file": "node0", "key-secret": "keysec0", "size": 18446744073709551104}}} {"return": {}} Job failed: The requested file size is too large {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "luks", "file": "node0", "key-secret": "keysec0", "size": 9223372036854775808}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "luks", "file": "node0", "key-secret": "keysec0", "size": 9223372036854775808}}} {"return": {}} Job failed: The requested file size is too large {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "luks", "file": "node0", "key-secret": "keysec0", "size": 9223372036854775296}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "luks", "file": "node0", "key-secret": "keysec0", "size": 9223372036854775296}}} {"return": {}} Job failed: The requested file size is too large {"execute": "job-dismiss", "arguments": {"id": "job0"}} @@ -181,13 +181,13 @@ Job failed: The requested file size is too large === Resize image with invalid sizes === -{"execute": "block_resize", "arguments": {"node_name": "node1", "size": 9223372036854775296}} +{"execute": "block_resize", "arguments": {"node-name": "node1", "size": 9223372036854775296}} {"error": {"class": "GenericError", "desc": "The requested file size is too large"}} -{"execute": "block_resize", "arguments": {"node_name": "node1", "size": 9223372036854775808}} +{"execute": "block_resize", "arguments": {"node-name": "node1", "size": 9223372036854775808}} {"error": {"class": "GenericError", "desc": "Invalid parameter type for 'size', expected: integer"}} -{"execute": "block_resize", "arguments": {"node_name": "node1", "size": 18446744073709551104}} +{"execute": "block_resize", "arguments": {"node-name": "node1", "size": 18446744073709551104}} {"error": {"class": "GenericError", "desc": "Invalid parameter type for 'size', expected: integer"}} -{"execute": "block_resize", "arguments": {"node_name": "node1", "size": -9223372036854775808}} +{"execute": "block_resize", "arguments": {"node-name": "node1", "size": -9223372036854775808}} {"error": {"class": "GenericError", "desc": "Parameter 'size' expects a >0 size"}} image: json:{"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_IMG"}, "key-secret": "keysec0"} file format: IMGFMT diff --git a/tests/qemu-iotests/211 b/tests/qemu-iotests/211 index 7b7985db6c..6afc894f76 100755 --- a/tests/qemu-iotests/211 +++ b/tests/qemu-iotests/211 @@ -27,11 +27,14 @@ iotests.verify_image_format(supported_fmts=['vdi']) iotests.verify_protocol(supported=['file']) def blockdev_create(vm, options): - result = vm.qmp_log('blockdev-create', job_id='job0', options=options) + result = vm.qmp_log('blockdev-create', job_id='job0', options=options, + filters=[iotests.filter_qmp_testfiles]) if 'return' in result: assert result['return'] == {} - vm.run_job('job0') + error = vm.run_job('job0') + if error and 'Could not allocate bmap' in error: + iotests.notrun('Insufficient memory') iotests.log("") with iotests.FilePath('t.vdi') as disk_path, \ @@ -51,7 +54,7 @@ with iotests.FilePath('t.vdi') as disk_path, \ 'size': 0 }) vm.qmp_log('blockdev-add', driver='file', filename=disk_path, - node_name='imgfile') + node_name='imgfile', filters=[iotests.filter_qmp_testfiles]) blockdev_create(vm, { 'driver': imgfmt, 'file': 'imgfile', diff --git a/tests/qemu-iotests/211.out b/tests/qemu-iotests/211.out index eebb0ea086..682adc2a10 100644 --- a/tests/qemu-iotests/211.out +++ b/tests/qemu-iotests/211.out @@ -1,13 +1,13 @@ === Successful image creation (defaults) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "node_name": "imgfile"}} +{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "node-name": "imgfile"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": "imgfile", "size": 134217728}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": "imgfile", "size": 134217728}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -21,12 +21,12 @@ cluster_size: 1048576 === Successful image creation (explicit defaults) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi"}, "preallocation": "off", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi"}, "preallocation": "off", "size": 67108864}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -40,12 +40,12 @@ cluster_size: 1048576 === Successful image creation (with non-default options) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi"}, "preallocation": "metadata", "size": 33554432}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi"}, "preallocation": "metadata", "size": 33554432}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -60,7 +60,7 @@ cluster_size: 1048576 === Invalid BlockdevRef === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": "this doesn't exist", "size": 33554432}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": "this doesn't exist", "size": 33554432}}} {"return": {}} Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist {"execute": "job-dismiss", "arguments": {"id": "job0"}} @@ -68,7 +68,7 @@ Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exi === Zero size === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -80,7 +80,7 @@ cluster_size: 1048576 === Maximum size === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 562949819203584}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 562949819203584}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -92,19 +92,19 @@ cluster_size: 1048576 === Invalid sizes === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 18446744073709551104}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 18446744073709551104}}} {"return": {}} Job failed: Unsupported VDI image size (size is 0xfffffffffffffe00, max supported is 0x1fffff8000000) {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 9223372036854775808}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 9223372036854775808}}} {"return": {}} Job failed: Unsupported VDI image size (size is 0x8000000000000000, max supported is 0x1fffff8000000) {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 562949819203585}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 562949819203585}}} {"return": {}} Job failed: Unsupported VDI image size (size is 0x1fffff8000001, max supported is 0x1fffff8000000) {"execute": "job-dismiss", "arguments": {"id": "job0"}} diff --git a/tests/qemu-iotests/212 b/tests/qemu-iotests/212 index 95c8810d83..42b74f208b 100755 --- a/tests/qemu-iotests/212 +++ b/tests/qemu-iotests/212 @@ -27,7 +27,8 @@ iotests.verify_image_format(supported_fmts=['parallels']) iotests.verify_protocol(supported=['file']) def blockdev_create(vm, options): - result = vm.qmp_log('blockdev-create', job_id='job0', options=options) + result = vm.qmp_log('blockdev-create', job_id='job0', options=options, + filters=[iotests.filter_qmp_testfiles]) if 'return' in result: assert result['return'] == {} @@ -51,7 +52,7 @@ with iotests.FilePath('t.parallels') as disk_path, \ 'size': 0 }) vm.qmp_log('blockdev-add', driver='file', filename=disk_path, - node_name='imgfile') + node_name='imgfile', filters=[iotests.filter_qmp_testfiles]) blockdev_create(vm, { 'driver': imgfmt, 'file': 'imgfile', diff --git a/tests/qemu-iotests/212.out b/tests/qemu-iotests/212.out index 01da467282..22810720cf 100644 --- a/tests/qemu-iotests/212.out +++ b/tests/qemu-iotests/212.out @@ -1,13 +1,13 @@ === Successful image creation (defaults) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels", "node_name": "imgfile"}} +{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels", "node-name": "imgfile"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "imgfile", "size": 134217728}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "parallels", "file": "imgfile", "size": 134217728}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -18,12 +18,12 @@ virtual size: 128M (134217728 bytes) === Successful image creation (explicit defaults) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 1048576, "driver": "parallels", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels"}, "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 1048576, "driver": "parallels", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels"}, "size": 67108864}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -34,12 +34,12 @@ virtual size: 64M (67108864 bytes) === Successful image creation (with non-default options) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 65536, "driver": "parallels", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels"}, "size": 33554432}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 65536, "driver": "parallels", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels"}, "size": 33554432}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -50,7 +50,7 @@ virtual size: 32M (33554432 bytes) === Invalid BlockdevRef === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "this doesn't exist", "size": 33554432}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "parallels", "file": "this doesn't exist", "size": 33554432}}} {"return": {}} Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist {"execute": "job-dismiss", "arguments": {"id": "job0"}} @@ -58,7 +58,7 @@ Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exi === Zero size === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -69,7 +69,7 @@ virtual size: 0 (0 bytes) === Maximum size === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 4503599627369984}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 4503599627369984}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -80,31 +80,31 @@ virtual size: 4096T (4503599627369984 bytes) === Invalid sizes === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 1234}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 1234}}} {"return": {}} Job failed: Image size must be a multiple of 512 bytes {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 18446744073709551104}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 18446744073709551104}}} {"return": {}} Job failed: Image size is too large for this cluster size {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 9223372036854775808}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 9223372036854775808}}} {"return": {}} Job failed: Image size is too large for this cluster size {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 9223372036854775296}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 9223372036854775296}}} {"return": {}} Job failed: Image size is too large for this cluster size {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 4503599627370497}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 4503599627370497}}} {"return": {}} Job failed: Image size is too large for this cluster size {"execute": "job-dismiss", "arguments": {"id": "job0"}} @@ -112,43 +112,43 @@ Job failed: Image size is too large for this cluster size === Invalid cluster size === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 1234, "driver": "parallels", "file": "node0", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 1234, "driver": "parallels", "file": "node0", "size": 67108864}}} {"return": {}} Job failed: Cluster size must be a multiple of 512 bytes {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 128, "driver": "parallels", "file": "node0", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 128, "driver": "parallels", "file": "node0", "size": 67108864}}} {"return": {}} Job failed: Cluster size must be a multiple of 512 bytes {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 4294967296, "driver": "parallels", "file": "node0", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 4294967296, "driver": "parallels", "file": "node0", "size": 67108864}}} {"return": {}} Job failed: Cluster size is too large {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 9223372036854775808, "driver": "parallels", "file": "node0", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 9223372036854775808, "driver": "parallels", "file": "node0", "size": 67108864}}} {"return": {}} Job failed: Cluster size is too large {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 18446744073709551104, "driver": "parallels", "file": "node0", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 18446744073709551104, "driver": "parallels", "file": "node0", "size": 67108864}}} {"return": {}} Job failed: Cluster size is too large {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 0, "driver": "parallels", "file": "node0", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 0, "driver": "parallels", "file": "node0", "size": 67108864}}} {"return": {}} Job failed: Image size is too large for this cluster size {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 512, "driver": "parallels", "file": "node0", "size": 281474976710656}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 512, "driver": "parallels", "file": "node0", "size": 281474976710656}}} {"return": {}} Job failed: Image size is too large for this cluster size {"execute": "job-dismiss", "arguments": {"id": "job0"}} diff --git a/tests/qemu-iotests/213 b/tests/qemu-iotests/213 index 4054439e3c..5604f3cebb 100755 --- a/tests/qemu-iotests/213 +++ b/tests/qemu-iotests/213 @@ -27,7 +27,8 @@ iotests.verify_image_format(supported_fmts=['vhdx']) iotests.verify_protocol(supported=['file']) def blockdev_create(vm, options): - result = vm.qmp_log('blockdev-create', job_id='job0', options=options) + result = vm.qmp_log('blockdev-create', job_id='job0', options=options, + filters=[iotests.filter_qmp_testfiles]) if 'return' in result: assert result['return'] == {} @@ -51,7 +52,7 @@ with iotests.FilePath('t.vhdx') as disk_path, \ 'size': 0 }) vm.qmp_log('blockdev-add', driver='file', filename=disk_path, - node_name='imgfile') + node_name='imgfile', filters=[iotests.filter_qmp_testfiles]) blockdev_create(vm, { 'driver': imgfmt, 'file': 'imgfile', diff --git a/tests/qemu-iotests/213.out b/tests/qemu-iotests/213.out index 0c9d65b2fe..169083e08e 100644 --- a/tests/qemu-iotests/213.out +++ b/tests/qemu-iotests/213.out @@ -1,13 +1,13 @@ === Successful image creation (defaults) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx", "node_name": "imgfile"}} +{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx", "node-name": "imgfile"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "imgfile", "size": 134217728}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "imgfile", "size": 134217728}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -19,12 +19,12 @@ cluster_size: 8388608 === Successful image creation (explicit defaults) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"block-size": 8388608, "block-state-zero": true, "driver": "vhdx", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx"}, "log-size": 1048576, "size": 67108864, "subformat": "dynamic"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"block-size": 8388608, "block-state-zero": true, "driver": "vhdx", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx"}, "log-size": 1048576, "size": 67108864, "subformat": "dynamic"}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -36,12 +36,12 @@ cluster_size: 8388608 === Successful image creation (with non-default options) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"block-size": 268435456, "block-state-zero": false, "driver": "vhdx", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx"}, "log-size": 8388608, "size": 33554432, "subformat": "fixed"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"block-size": 268435456, "block-state-zero": false, "driver": "vhdx", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx"}, "log-size": 8388608, "size": 33554432, "subformat": "fixed"}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -53,7 +53,7 @@ cluster_size: 268435456 === Invalid BlockdevRef === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "this doesn't exist", "size": 33554432}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "this doesn't exist", "size": 33554432}}} {"return": {}} Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist {"execute": "job-dismiss", "arguments": {"id": "job0"}} @@ -61,7 +61,7 @@ Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exi === Zero size === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -73,7 +73,7 @@ cluster_size: 8388608 === Maximum size === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 70368744177664}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 70368744177664}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -85,25 +85,25 @@ cluster_size: 67108864 === Invalid sizes === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 18446744073709551104}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 18446744073709551104}}} {"return": {}} Job failed: Image size too large; max of 64TB {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 9223372036854775808}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 9223372036854775808}}} {"return": {}} Job failed: Image size too large; max of 64TB {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 9223372036854775296}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 9223372036854775296}}} {"return": {}} Job failed: Image size too large; max of 64TB {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 70368744177665}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 70368744177665}}} {"return": {}} Job failed: Image size too large; max of 64TB {"execute": "job-dismiss", "arguments": {"id": "job0"}} @@ -111,31 +111,31 @@ Job failed: Image size too large; max of 64TB === Invalid block size === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"block-size": 1234567, "driver": "vhdx", "file": "node0", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"block-size": 1234567, "driver": "vhdx", "file": "node0", "size": 67108864}}} {"return": {}} Job failed: Block size must be a multiple of 1 MB {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"block-size": 128, "driver": "vhdx", "file": "node0", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"block-size": 128, "driver": "vhdx", "file": "node0", "size": 67108864}}} {"return": {}} Job failed: Block size must be a multiple of 1 MB {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"block-size": 3145728, "driver": "vhdx", "file": "node0", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"block-size": 3145728, "driver": "vhdx", "file": "node0", "size": 67108864}}} {"return": {}} Job failed: Block size must be a power of two {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"block-size": 536870912, "driver": "vhdx", "file": "node0", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"block-size": 536870912, "driver": "vhdx", "file": "node0", "size": 67108864}}} {"return": {}} Job failed: Block size must not exceed 268435456 {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"block-size": 0, "driver": "vhdx", "file": "node0", "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"block-size": 0, "driver": "vhdx", "file": "node0", "size": 67108864}}} {"return": {}} Job failed: Block size must be a multiple of 1 MB {"execute": "job-dismiss", "arguments": {"id": "job0"}} @@ -143,25 +143,25 @@ Job failed: Block size must be a multiple of 1 MB === Invalid log size === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "log-size": 1234567, "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "log-size": 1234567, "size": 67108864}}} {"return": {}} Job failed: Log size must be a multiple of 1 MB {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "log-size": 128, "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "log-size": 128, "size": 67108864}}} {"return": {}} Job failed: Log size must be a multiple of 1 MB {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "log-size": 4294967296, "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "log-size": 4294967296, "size": 67108864}}} {"return": {}} Job failed: Log size must be smaller than 4 GB {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "log-size": 0, "size": 67108864}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "log-size": 0, "size": 67108864}}} {"return": {}} Job failed: Log size must be a multiple of 1 MB {"execute": "job-dismiss", "arguments": {"id": "job0"}} diff --git a/tests/qemu-iotests/224 b/tests/qemu-iotests/224 new file mode 100755 index 0000000000..b4dfaa639f --- /dev/null +++ b/tests/qemu-iotests/224 @@ -0,0 +1,139 @@ +#!/usr/bin/env python +# +# Test json:{} filenames with qemu-internal BDSs +# (the one of commit, to be precise) +# +# Copyright (C) 2018 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: Max Reitz <mreitz@redhat.com> + +import iotests +from iotests import log, qemu_img, qemu_io_silent, filter_qmp_testfiles, \ + filter_qmp_imgfmt +import json + +# Need backing file support (for arbitrary backing formats) +iotests.verify_image_format(supported_fmts=['qcow2', 'qcow', 'qed']) +iotests.verify_platform(['linux']) + + +# There are two variations of this test: +# (1) We do not set filter_node_name. In that case, the commit_top +# driver should not appear anywhere. +# (2) We do set filter_node_name. In that case, it should appear. +# +# This for loop executes both. +for filter_node_name in False, True: + log('') + log('--- filter_node_name: %s ---' % filter_node_name) + log('') + + with iotests.FilePath('base.img') as base_img_path, \ + iotests.FilePath('mid.img') as mid_img_path, \ + iotests.FilePath('top.img') as top_img_path, \ + iotests.VM() as vm: + + assert qemu_img('create', '-f', iotests.imgfmt, + base_img_path, '64M') == 0 + assert qemu_img('create', '-f', iotests.imgfmt, '-b', base_img_path, + mid_img_path) == 0 + assert qemu_img('create', '-f', iotests.imgfmt, '-b', mid_img_path, + top_img_path) == 0 + + # Something to commit + assert qemu_io_silent(mid_img_path, '-c', 'write -P 1 0 1M') == 0 + + vm.launch() + + # Change the bottom-most image's backing file (to null-co://) + # to enforce json:{} filenames + vm.qmp_log('blockdev-add', + node_name='top', + driver=iotests.imgfmt, + file={ + 'driver': 'file', + 'filename': top_img_path + }, + backing={ + 'node-name': 'mid', + 'driver': iotests.imgfmt, + 'file': { + 'driver': 'file', + 'filename': mid_img_path + }, + 'backing': { + 'node-name': 'base', + 'driver': iotests.imgfmt, + 'file': { + 'driver': 'file', + 'filename': base_img_path + }, + 'backing': { + 'driver': 'null-co' + } + } + }, + filters=[filter_qmp_testfiles, filter_qmp_imgfmt]) + + # As long as block-commit does not accept node names, we have to + # get our mid/base filenames here + mid_name = vm.node_info('mid')['image']['filename'] + base_name = vm.node_info('base')['image']['filename'] + + assert mid_name[:5] == 'json:' + assert base_name[:5] == 'json:' + + # Start the block job + if filter_node_name: + vm.qmp_log('block-commit', + job_id='commit', + device='top', + filter_node_name='filter_node', + top=mid_name, + base=base_name, + speed=1, + filters=[filter_qmp_testfiles, filter_qmp_imgfmt]) + else: + vm.qmp_log('block-commit', + job_id='commit', + device='top', + top=mid_name, + base=base_name, + speed=1, + filters=[filter_qmp_testfiles, filter_qmp_imgfmt]) + + vm.qmp_log('job-pause', id='commit') + + # Get and parse top's json:{} filename + top_name = vm.node_info('top')['image']['filename'] + + vm.shutdown() + + assert top_name[:5] == 'json:' + top_options = json.loads(top_name[5:]) + + if filter_node_name: + # This should be present and set + assert top_options['backing']['driver'] == 'commit_top' + # And the mid image is commit_top's backing image + mid_options = top_options['backing']['backing'] + else: + # The mid image should appear as the immediate backing BDS + # of top + mid_options = top_options['backing'] + + assert mid_options['driver'] == iotests.imgfmt + assert mid_options['file']['filename'] == mid_img_path diff --git a/tests/qemu-iotests/224.out b/tests/qemu-iotests/224.out new file mode 100644 index 0000000000..23374a1d29 --- /dev/null +++ b/tests/qemu-iotests/224.out @@ -0,0 +1,18 @@ + +--- filter_node_name: False --- + +{"execute": "blockdev-add", "arguments": {"backing": {"backing": {"backing": {"driver": "null-co"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-base.img"}, "node-name": "base"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-mid.img"}, "node-name": "mid"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}, "node-name": "top"}} +{"return": {}} +{"execute": "block-commit", "arguments": {"base": "json:{\"backing\": {\"driver\": \"null-co\"}, \"driver\": \"IMGFMT\", \"file\": {\"driver\": \"file\", \"filename\": \"TEST_DIR/PID-base.img\"}}", "device": "top", "job-id": "commit", "speed": 1, "top": "json:{\"backing\": {\"backing\": {\"driver\": \"null-co\"}, \"driver\": \"IMGFMT\", \"file\": {\"driver\": \"file\", \"filename\": \"TEST_DIR/PID-base.img\"}}, \"driver\": \"IMGFMT\", \"file\": {\"driver\": \"file\", \"filename\": \"TEST_DIR/PID-mid.img\"}}"}} +{"return": {}} +{"execute": "job-pause", "arguments": {"id": "commit"}} +{"return": {}} + +--- filter_node_name: True --- + +{"execute": "blockdev-add", "arguments": {"backing": {"backing": {"backing": {"driver": "null-co"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-base.img"}, "node-name": "base"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-mid.img"}, "node-name": "mid"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}, "node-name": "top"}} +{"return": {}} +{"execute": "block-commit", "arguments": {"base": "json:{\"backing\": {\"driver\": \"null-co\"}, \"driver\": \"IMGFMT\", \"file\": {\"driver\": \"file\", \"filename\": \"TEST_DIR/PID-base.img\"}}", "device": "top", "filter-node-name": "filter_node", "job-id": "commit", "speed": 1, "top": "json:{\"backing\": {\"backing\": {\"driver\": \"null-co\"}, \"driver\": \"IMGFMT\", \"file\": {\"driver\": \"file\", \"filename\": \"TEST_DIR/PID-base.img\"}}, \"driver\": \"IMGFMT\", \"file\": {\"driver\": \"file\", \"filename\": \"TEST_DIR/PID-mid.img\"}}"}} +{"return": {}} +{"execute": "job-pause", "arguments": {"id": "commit"}} +{"return": {}} diff --git a/tests/qemu-iotests/228 b/tests/qemu-iotests/228 new file mode 100755 index 0000000000..9a50afd205 --- /dev/null +++ b/tests/qemu-iotests/228 @@ -0,0 +1,239 @@ +#!/usr/bin/env python +# +# Test for when a backing file is considered overridden (thus, a +# json:{} filename is generated for the overlay) and when it is not +# +# Copyright (C) 2018 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: Max Reitz <mreitz@redhat.com> + +import iotests +from iotests import log, qemu_img, filter_testfiles, filter_imgfmt, \ + filter_qmp_testfiles, filter_qmp_imgfmt + +# Need backing file and change-backing-file support +iotests.verify_image_format(supported_fmts=['qcow2', 'qed']) +iotests.verify_platform(['linux']) + + +def log_node_info(node): + log('') + + log('bs->filename: ' + node['image']['filename'], + filters=[filter_testfiles, filter_imgfmt]) + log('bs->backing_file: ' + node['backing_file'], + filters=[filter_testfiles, filter_imgfmt]) + + if 'backing-image' in node['image']: + log('bs->backing->bs->filename: ' + + node['image']['backing-image']['filename'], + filters=[filter_testfiles, filter_imgfmt]) + else: + log('bs->backing: (none)') + + log('') + + +with iotests.FilePath('base.img') as base_img_path, \ + iotests.FilePath('top.img') as top_img_path, \ + iotests.VM() as vm: + + assert qemu_img('create', '-f', iotests.imgfmt, base_img_path, '64M') == 0 + # Choose a funny way to describe the backing filename + assert qemu_img('create', '-f', iotests.imgfmt, '-b', + 'file:' + base_img_path, top_img_path) == 0 + + vm.launch() + + log('--- Implicit backing file ---') + log('') + + vm.qmp_log('blockdev-add', + node_name='node0', + driver=iotests.imgfmt, + file={ + 'driver': 'file', + 'filename': top_img_path + }, + filters=[filter_qmp_testfiles, filter_qmp_imgfmt]) + + # Filename should be plain, and the backing filename should not + # contain the "file:" prefix + log_node_info(vm.node_info('node0')) + + vm.qmp_log('blockdev-del', node_name='node0') + + log('') + log('--- change-backing-file ---') + log('') + + vm.qmp_log('blockdev-add', + node_name='node0', + driver=iotests.imgfmt, + file={ + 'driver': 'file', + 'filename': top_img_path + }, + filters=[filter_qmp_testfiles, filter_qmp_imgfmt]) + + # Changing the backing file to a qemu-reported filename should + # result in qemu accepting the corresponding BDS as the implicit + # backing BDS (and thus not generate a json:{} filename). + # So, first, query the backing filename. + + backing_filename = \ + vm.node_info('node0')['image']['backing-image']['filename'] + + # Next, change the backing file to something different + + vm.qmp_log('change-backing-file', + image_node_name='node0', + device='node0', + backing_file='null-co://', + filters=[filter_qmp_testfiles]) + + # Now, verify that we get a json:{} filename + # (Image header says "null-co://", actual backing file still is + # base_img_path) + + log_node_info(vm.node_info('node0')) + + # Change it back + # (To get header and backing file in sync) + + vm.qmp_log('change-backing-file', + image_node_name='node0', + device='node0', + backing_file=backing_filename, + filters=[filter_qmp_testfiles]) + + # And verify that we get our original results + + log_node_info(vm.node_info('node0')) + + # Finally, try a "file:" prefix. While this is actually what we + # originally had in the image header, qemu will not reopen the + # backing file here, so it cannot verify that this filename + # "resolves" to the actual backing BDS's filename and will thus + # consider both to be different. + # (This may be fixed in the future.) + + vm.qmp_log('change-backing-file', + image_node_name='node0', + device='node0', + backing_file=('file:' + backing_filename), + filters=[filter_qmp_testfiles]) + + # So now we should get a json:{} filename + + log_node_info(vm.node_info('node0')) + + # Remove and re-attach so we can see that (as in our first try), + # opening the image anew helps qemu resolve the header backing + # filename. + + vm.qmp_log('blockdev-del', node_name='node0') + + vm.qmp_log('blockdev-add', + node_name='node0', + driver=iotests.imgfmt, + file={ + 'driver': 'file', + 'filename': top_img_path + }, + filters=[filter_qmp_testfiles, filter_qmp_imgfmt]) + + log_node_info(vm.node_info('node0')) + + vm.qmp_log('blockdev-del', node_name='node0') + + log('') + log('--- Override backing file ---') + log('') + + # For this test, we need the plain filename in the image header + # (because qemu cannot "canonicalize"/"resolve" the backing + # filename unless the backing file is opened implicitly with the + # overlay) + assert qemu_img('create', '-f', iotests.imgfmt, '-b', base_img_path, + top_img_path) == 0 + + # You can only reliably override backing options by using a node + # reference (or by specifying file.filename, but, well...) + vm.qmp_log('blockdev-add', node_name='null', driver='null-co') + + vm.qmp_log('blockdev-add', + node_name='node0', + driver=iotests.imgfmt, + file={ + 'driver': 'file', + 'filename': top_img_path + }, + backing='null', + filters=[filter_qmp_testfiles, filter_qmp_imgfmt]) + + # Should get a json:{} filename (and bs->backing_file is + # null-co://, because that field actually has not much to do + # with the header backing filename (except that it is changed by + # change-backing-file)) + + log_node_info(vm.node_info('node0')) + + # Detach the backing file by reopening the whole thing + + vm.qmp_log('blockdev-del', node_name='node0') + vm.qmp_log('blockdev-del', node_name='null') + + vm.qmp_log('blockdev-add', + node_name='node0', + driver=iotests.imgfmt, + file={ + 'driver': 'file', + 'filename': top_img_path + }, + backing=None, + filters=[filter_qmp_testfiles, filter_qmp_imgfmt]) + + # Should get a json:{} filename (because we overrode the backing + # file to not be there) + + log_node_info(vm.node_info('node0')) + + # Open the original backing file + + vm.qmp_log('blockdev-add', + node_name='original-backing', + driver=iotests.imgfmt, + file={ + 'driver': 'file', + 'filename': base_img_path + }, + filters=[filter_qmp_testfiles, filter_qmp_imgfmt]) + + # Attach the original backing file to its overlay + + vm.qmp_log('blockdev-snapshot', + node='original-backing', + overlay='node0') + + # This should give us the original plain result + + log_node_info(vm.node_info('node0')) + + vm.qmp_log('blockdev-del', node_name='node0') + vm.qmp_log('blockdev-del', node_name='original-backing') + + vm.shutdown() diff --git a/tests/qemu-iotests/228.out b/tests/qemu-iotests/228.out new file mode 100644 index 0000000000..4217df24fe --- /dev/null +++ b/tests/qemu-iotests/228.out @@ -0,0 +1,84 @@ +--- Implicit backing file --- + +{"execute": "blockdev-add", "arguments": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}, "node-name": "node0"}} +{"return": {}} + +bs->filename: TEST_DIR/PID-top.img +bs->backing_file: TEST_DIR/PID-base.img +bs->backing->bs->filename: TEST_DIR/PID-base.img + +{"execute": "blockdev-del", "arguments": {"node-name": "node0"}} +{"return": {}} + +--- change-backing-file --- + +{"execute": "blockdev-add", "arguments": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}, "node-name": "node0"}} +{"return": {}} +{"execute": "change-backing-file", "arguments": {"backing-file": "null-co://", "device": "node0", "image-node-name": "node0"}} +{"return": {}} + +bs->filename: json:{"backing": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-base.img"}}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}} +bs->backing_file: null-co:// +bs->backing->bs->filename: TEST_DIR/PID-base.img + +{"execute": "change-backing-file", "arguments": {"backing-file": "TEST_DIR/PID-base.img", "device": "node0", "image-node-name": "node0"}} +{"return": {}} + +bs->filename: TEST_DIR/PID-top.img +bs->backing_file: TEST_DIR/PID-base.img +bs->backing->bs->filename: TEST_DIR/PID-base.img + +{"execute": "change-backing-file", "arguments": {"backing-file": "file:TEST_DIR/PID-base.img", "device": "node0", "image-node-name": "node0"}} +{"return": {}} + +bs->filename: json:{"backing": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-base.img"}}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}} +bs->backing_file: file:TEST_DIR/PID-base.img +bs->backing->bs->filename: TEST_DIR/PID-base.img + +{"execute": "blockdev-del", "arguments": {"node-name": "node0"}} +{"return": {}} +{"execute": "blockdev-add", "arguments": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}, "node-name": "node0"}} +{"return": {}} + +bs->filename: TEST_DIR/PID-top.img +bs->backing_file: TEST_DIR/PID-base.img +bs->backing->bs->filename: TEST_DIR/PID-base.img + +{"execute": "blockdev-del", "arguments": {"node-name": "node0"}} +{"return": {}} + +--- Override backing file --- + +{"execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "null"}} +{"return": {}} +{"execute": "blockdev-add", "arguments": {"backing": "null", "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}, "node-name": "node0"}} +{"return": {}} + +bs->filename: json:{"backing": {"driver": "null-co"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}} +bs->backing_file: null-co:// +bs->backing->bs->filename: null-co:// + +{"execute": "blockdev-del", "arguments": {"node-name": "node0"}} +{"return": {}} +{"execute": "blockdev-del", "arguments": {"node-name": "null"}} +{"return": {}} +{"execute": "blockdev-add", "arguments": {"backing": null, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}, "node-name": "node0"}} +{"return": {}} + +bs->filename: json:{"backing": null, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}} +bs->backing_file: TEST_DIR/PID-base.img +bs->backing: (none) + +{"execute": "blockdev-add", "arguments": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-base.img"}, "node-name": "original-backing"}} +{"return": {}} +{"execute": "blockdev-snapshot", "arguments": {"node": "original-backing", "overlay": "node0"}} +{"return": {}} + +bs->filename: TEST_DIR/PID-top.img +bs->backing_file: TEST_DIR/PID-base.img +bs->backing->bs->filename: TEST_DIR/PID-base.img + +{"execute": "blockdev-del", "arguments": {"node-name": "node0"}} +{"return": {}} +{"execute": "blockdev-del", "arguments": {"node-name": "original-backing"}} +{"return": {}} diff --git a/tests/qemu-iotests/232 b/tests/qemu-iotests/232 index 0708b8b155..e48bc8f5db 100755 --- a/tests/qemu-iotests/232 +++ b/tests/qemu-iotests/232 @@ -29,7 +29,6 @@ status=1 # failure is the default! _cleanup() { _cleanup_test_img - rm -f $TEST_IMG.snap } trap "_cleanup; exit \$status" 0 1 2 3 15 @@ -70,6 +69,10 @@ size=128M _make_test_img $size +if [ -n "$TEST_IMG_FILE" ]; then + TEST_IMG=$TEST_IMG_FILE +fi + echo echo "=== -drive with read-write image: read-only/auto-read-only combinations ===" echo diff --git a/tests/qemu-iotests/237 b/tests/qemu-iotests/237 index 251771d7fb..06897f8c87 100755 --- a/tests/qemu-iotests/237 +++ b/tests/qemu-iotests/237 @@ -27,7 +27,8 @@ from iotests import imgfmt iotests.verify_image_format(supported_fmts=['vmdk']) def blockdev_create(vm, options): - result = vm.qmp_log('blockdev-create', job_id='job0', options=options) + result = vm.qmp_log('blockdev-create', job_id='job0', options=options, + filters=[iotests.filter_qmp_testfiles]) if 'return' in result: assert result['return'] == {} @@ -54,7 +55,7 @@ with iotests.FilePath('t.vmdk') as disk_path, \ 'size': 0 }) vm.qmp_log('blockdev-add', driver='file', filename=disk_path, - node_name='imgfile') + node_name='imgfile', filters=[iotests.filter_qmp_testfiles]) blockdev_create(vm, { 'driver': imgfmt, 'file': 'imgfile', @@ -223,7 +224,7 @@ with iotests.FilePath('t.vmdk') as disk_path, \ iotests.log("= %s %d =" % (subfmt, size)) iotests.log("") - num_extents = math.ceil(size / 2.0**31) + num_extents = int(math.ceil(size / 2.0**31)) extents = [ "ext%d" % (i) for i in range(1, num_extents + 1) ] vm.launch() diff --git a/tests/qemu-iotests/237.out b/tests/qemu-iotests/237.out index 241c864369..2aaa68f672 100644 --- a/tests/qemu-iotests/237.out +++ b/tests/qemu-iotests/237.out @@ -1,13 +1,13 @@ === Successful image creation (defaults) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "node_name": "imgfile"}} +{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "node-name": "imgfile"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "file": "imgfile", "size": 5368709120}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "file": "imgfile", "size": 5368709120}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -29,12 +29,12 @@ Format specific information: === Successful image creation (inline blockdev-add, explicit defaults) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "ide", "driver": "vmdk", "extents": [], "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk"}, "hwversion": "4", "size": 67108864, "subformat": "monolithicSparse", "zeroed-grain": false}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": "ide", "driver": "vmdk", "extents": [], "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk"}, "hwversion": "4", "size": 67108864, "subformat": "monolithicSparse", "zeroed-grain": false}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -56,12 +56,12 @@ Format specific information: === Successful image creation (with non-default options) === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "size": 0}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "size": 0}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "buslogic", "driver": "vmdk", "extents": [], "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk"}, "size": 33554432, "subformat": "monolithicSparse", "zeroed-grain": true}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": "buslogic", "driver": "vmdk", "extents": [], "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk"}, "size": 33554432, "subformat": "monolithicSparse", "zeroed-grain": true}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -83,7 +83,7 @@ Format specific information: === Invalid BlockdevRef === -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "file": "this doesn't exist", "size": 33554432}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "file": "this doesn't exist", "size": 33554432}}} {"return": {}} Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist {"execute": "job-dismiss", "arguments": {"id": "job0"}} @@ -93,38 +93,38 @@ Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exi == Valid adapter types == -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "ide", "driver": "vmdk", "file": "node0", "size": 33554432}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": "ide", "driver": "vmdk", "file": "node0", "size": 33554432}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "buslogic", "driver": "vmdk", "file": "node0", "size": 33554432}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": "buslogic", "driver": "vmdk", "file": "node0", "size": 33554432}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "lsilogic", "driver": "vmdk", "file": "node0", "size": 33554432}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": "lsilogic", "driver": "vmdk", "file": "node0", "size": 33554432}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "legacyESX", "driver": "vmdk", "file": "node0", "size": 33554432}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": "legacyESX", "driver": "vmdk", "file": "node0", "size": 33554432}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} == Invalid adapter types == -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "foo", "driver": "vmdk", "file": "node0", "size": 33554432}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": "foo", "driver": "vmdk", "file": "node0", "size": 33554432}}} {"error": {"class": "GenericError", "desc": "Invalid parameter 'foo'"}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "IDE", "driver": "vmdk", "file": "node0", "size": 33554432}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": "IDE", "driver": "vmdk", "file": "node0", "size": 33554432}}} {"error": {"class": "GenericError", "desc": "Invalid parameter 'IDE'"}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "legacyesx", "driver": "vmdk", "file": "node0", "size": 33554432}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": "legacyesx", "driver": "vmdk", "file": "node0", "size": 33554432}}} {"error": {"class": "GenericError", "desc": "Invalid parameter 'legacyesx'"}} -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": 1, "driver": "vmdk", "file": "node0", "size": 33554432}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": 1, "driver": "vmdk", "file": "node0", "size": 33554432}}} {"error": {"class": "GenericError", "desc": "Invalid parameter type for 'options.adapter-type', expected: string"}} === Other subformats === @@ -137,7 +137,7 @@ Formatting 'TEST_DIR/PID-t.vmdk.3', fmt=vmdk size=0 compat6=off hwversion=undefi == Missing extent == -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "file": "node0", "size": 33554432, "subformat": "monolithicFlat"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "file": "node0", "size": 33554432, "subformat": "monolithicFlat"}}} {"return": {}} Job failed: Extent [0] not specified {"execute": "job-dismiss", "arguments": {"id": "job0"}} @@ -145,14 +145,14 @@ Job failed: Extent [0] not specified == Correct extent == -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 33554432, "subformat": "monolithicFlat"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 33554432, "subformat": "monolithicFlat"}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} == Extra extent == -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 512, "subformat": "monolithicFlat"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 512, "subformat": "monolithicFlat"}}} {"return": {}} Job failed: List of extents contains unused extents {"execute": "job-dismiss", "arguments": {"id": "job0"}} @@ -162,7 +162,7 @@ Job failed: List of extents contains unused extents = twoGbMaxExtentFlat 512 = -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 512, "subformat": "twoGbMaxExtentFlat"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 512, "subformat": "twoGbMaxExtentFlat"}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -182,7 +182,7 @@ Format specific information: = twoGbMaxExtentSparse 512 = -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 512, "subformat": "twoGbMaxExtentSparse"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 512, "subformat": "twoGbMaxExtentSparse"}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -204,7 +204,7 @@ Format specific information: = twoGbMaxExtentFlat 1073741824 = -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 1073741824, "subformat": "twoGbMaxExtentFlat"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 1073741824, "subformat": "twoGbMaxExtentFlat"}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -224,7 +224,7 @@ Format specific information: = twoGbMaxExtentSparse 1073741824 = -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 1073741824, "subformat": "twoGbMaxExtentSparse"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 1073741824, "subformat": "twoGbMaxExtentSparse"}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -246,7 +246,7 @@ Format specific information: = twoGbMaxExtentFlat 2147483648 = -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 2147483648, "subformat": "twoGbMaxExtentFlat"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 2147483648, "subformat": "twoGbMaxExtentFlat"}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -266,7 +266,7 @@ Format specific information: = twoGbMaxExtentSparse 2147483648 = -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 2147483648, "subformat": "twoGbMaxExtentSparse"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 2147483648, "subformat": "twoGbMaxExtentSparse"}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -288,7 +288,7 @@ Format specific information: = twoGbMaxExtentFlat 5368709120 = -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 5368709120, "subformat": "twoGbMaxExtentFlat"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 5368709120, "subformat": "twoGbMaxExtentFlat"}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} @@ -316,7 +316,7 @@ Format specific information: = twoGbMaxExtentSparse 5368709120 = -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 5368709120, "subformat": "twoGbMaxExtentSparse"}}} +{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 5368709120, "subformat": "twoGbMaxExtentSparse"}}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index e15e7a7c8e..09a27f02d0 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -145,6 +145,7 @@ else TEST_IMG="nbd:127.0.0.1:10810" elif [ "$IMGPROTO" = "ssh" ]; then TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT + REMOTE_TEST_DIR="ssh://127.0.0.1$TEST_DIR" TEST_IMG="ssh://127.0.0.1$TEST_IMG_FILE" elif [ "$IMGPROTO" = "nfs" ]; then TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index fc4c416fa3..b5ca63cf72 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -224,9 +224,11 @@ 221 rw auto quick 222 rw auto quick 223 rw auto quick +224 rw auto quick 225 rw auto quick 226 auto quick 227 auto quick +228 rw auto quick 229 auto quick 231 auto quick 232 auto quick diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index b461f53abf..4910fb2005 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -76,14 +76,16 @@ def qemu_img(*args): sys.stderr.write('qemu-img received signal %i: %s\n' % (-exitcode, ' '.join(qemu_img_args + list(args)))) return exitcode -def ordered_qmp(qmsg): +def ordered_qmp(qmsg, conv_keys=True): # Dictionaries are not ordered prior to 3.6, therefore: if isinstance(qmsg, list): return [ordered_qmp(atom) for atom in qmsg] if isinstance(qmsg, dict): od = OrderedDict() for k, v in sorted(qmsg.items()): - od[k] = ordered_qmp(v) + if conv_keys: + k = k.replace('_', '-') + od[k] = ordered_qmp(v, conv_keys=False) return od return qmsg @@ -236,6 +238,12 @@ def image_size(img): r = qemu_img_pipe('info', '--output=json', '-f', imgfmt, img) return json.loads(r)['virtual-size'] +def is_str(val): + if sys.version_info.major >= 3: + return isinstance(val, str) + else: + return isinstance(val, str) or isinstance(val, unicode) + test_dir_re = re.compile(r"%s" % test_dir) def filter_test_dir(msg): return test_dir_re.sub("TEST_DIR", msg) @@ -283,7 +291,7 @@ def filter_testfiles(msg): def filter_qmp_testfiles(qmsg): def _filter(key, value): - if key == 'filename' or key == 'backing-file': + if is_str(value): return filter_testfiles(value) return value return filter_qmp(qmsg, _filter) @@ -304,6 +312,16 @@ def filter_img_info(output, filename): lines.append(line) return '\n'.join(lines) +def filter_imgfmt(msg): + return msg.replace(imgfmt, 'IMGFMT') + +def filter_qmp_imgfmt(qmsg): + def _filter(key, value): + if is_str(value): + return filter_imgfmt(value) + return value + return filter_qmp(qmsg, _filter) + def log(msg, filters=[], indent=None): '''Logs either a string message or a JSON serializable message (like QMP). If indent is provided, JSON serializable messages are pretty-printed.''' @@ -514,7 +532,9 @@ class VM(qtest.QEMUQtestMachine): log(result, filters, indent=indent) return result + # Returns None on success, and an error string on failure def run_job(self, job, auto_finalize=True, auto_dismiss=False): + error = None while True: for ev in self.get_qmp_events_filtered(wait=True): if ev['event'] == 'JOB_STATUS_CHANGE': @@ -523,16 +543,24 @@ class VM(qtest.QEMUQtestMachine): result = self.qmp('query-jobs') for j in result['return']: if j['id'] == job: + error = j['error'] log('Job failed: %s' % (j['error'])) elif status == 'pending' and not auto_finalize: self.qmp_log('job-finalize', id=job) elif status == 'concluded' and not auto_dismiss: self.qmp_log('job-dismiss', id=job) elif status == 'null': - return + return error else: iotests.log(ev) + def node_info(self, node_name): + nodes = self.qmp('query-named-block-nodes') + for x in nodes['return']: + if x['node-name'] == node_name: + return x + return None + index_re = re.compile(r'([^\[]+)\[([^\]]+)\]') diff --git a/tests/test-authz-list.c b/tests/test-authz-list.c new file mode 100644 index 0000000000..24347a6ac3 --- /dev/null +++ b/tests/test-authz-list.c @@ -0,0 +1,159 @@ +/* + * QEMU list file authorization object tests + * + * Copyright (c) 2018 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "qemu/osdep.h" + +#include "authz/list.h" + +static void test_authz_default_deny(void) +{ + QAuthZList *auth = qauthz_list_new("auth0", + QAUTHZ_LIST_POLICY_DENY, + &error_abort); + + g_assert(!qauthz_is_allowed(QAUTHZ(auth), "fred", &error_abort)); + + object_unparent(OBJECT(auth)); +} + +static void test_authz_default_allow(void) +{ + QAuthZList *auth = qauthz_list_new("auth0", + QAUTHZ_LIST_POLICY_ALLOW, + &error_abort); + + g_assert(qauthz_is_allowed(QAUTHZ(auth), "fred", &error_abort)); + + object_unparent(OBJECT(auth)); +} + +static void test_authz_explicit_deny(void) +{ + QAuthZList *auth = qauthz_list_new("auth0", + QAUTHZ_LIST_POLICY_ALLOW, + &error_abort); + + qauthz_list_append_rule(auth, "fred", QAUTHZ_LIST_POLICY_DENY, + QAUTHZ_LIST_FORMAT_EXACT, &error_abort); + + g_assert(!qauthz_is_allowed(QAUTHZ(auth), "fred", &error_abort)); + + object_unparent(OBJECT(auth)); +} + +static void test_authz_explicit_allow(void) +{ + QAuthZList *auth = qauthz_list_new("auth0", + QAUTHZ_LIST_POLICY_DENY, + &error_abort); + + qauthz_list_append_rule(auth, "fred", QAUTHZ_LIST_POLICY_ALLOW, + QAUTHZ_LIST_FORMAT_EXACT, &error_abort); + + g_assert(qauthz_is_allowed(QAUTHZ(auth), "fred", &error_abort)); + + object_unparent(OBJECT(auth)); +} + + +static void test_authz_complex(void) +{ + QAuthZList *auth = qauthz_list_new("auth0", + QAUTHZ_LIST_POLICY_DENY, + &error_abort); + + qauthz_list_append_rule(auth, "fred", QAUTHZ_LIST_POLICY_ALLOW, + QAUTHZ_LIST_FORMAT_EXACT, &error_abort); + qauthz_list_append_rule(auth, "bob", QAUTHZ_LIST_POLICY_ALLOW, + QAUTHZ_LIST_FORMAT_EXACT, &error_abort); + qauthz_list_append_rule(auth, "dan", QAUTHZ_LIST_POLICY_DENY, + QAUTHZ_LIST_FORMAT_EXACT, &error_abort); + qauthz_list_append_rule(auth, "dan*", QAUTHZ_LIST_POLICY_ALLOW, + QAUTHZ_LIST_FORMAT_GLOB, &error_abort); + + g_assert(qauthz_is_allowed(QAUTHZ(auth), "fred", &error_abort)); + g_assert(qauthz_is_allowed(QAUTHZ(auth), "bob", &error_abort)); + g_assert(!qauthz_is_allowed(QAUTHZ(auth), "dan", &error_abort)); + g_assert(qauthz_is_allowed(QAUTHZ(auth), "danb", &error_abort)); + + object_unparent(OBJECT(auth)); +} + +static void test_authz_add_remove(void) +{ + QAuthZList *auth = qauthz_list_new("auth0", + QAUTHZ_LIST_POLICY_ALLOW, + &error_abort); + + g_assert_cmpint(qauthz_list_append_rule(auth, "fred", + QAUTHZ_LIST_POLICY_ALLOW, + QAUTHZ_LIST_FORMAT_EXACT, + &error_abort), + ==, 0); + g_assert_cmpint(qauthz_list_append_rule(auth, "bob", + QAUTHZ_LIST_POLICY_ALLOW, + QAUTHZ_LIST_FORMAT_EXACT, + &error_abort), + ==, 1); + g_assert_cmpint(qauthz_list_append_rule(auth, "dan", + QAUTHZ_LIST_POLICY_DENY, + QAUTHZ_LIST_FORMAT_EXACT, + &error_abort), + ==, 2); + g_assert_cmpint(qauthz_list_append_rule(auth, "frank", + QAUTHZ_LIST_POLICY_DENY, + QAUTHZ_LIST_FORMAT_EXACT, + &error_abort), + ==, 3); + + g_assert(!qauthz_is_allowed(QAUTHZ(auth), "dan", &error_abort)); + + g_assert_cmpint(qauthz_list_delete_rule(auth, "dan"), + ==, 2); + + g_assert(qauthz_is_allowed(QAUTHZ(auth), "dan", &error_abort)); + + g_assert_cmpint(qauthz_list_insert_rule(auth, "dan", + QAUTHZ_LIST_POLICY_DENY, + QAUTHZ_LIST_FORMAT_EXACT, + 2, + &error_abort), + ==, 2); + + g_assert(!qauthz_is_allowed(QAUTHZ(auth), "dan", &error_abort)); + + object_unparent(OBJECT(auth)); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + module_call_init(MODULE_INIT_QOM); + + g_test_add_func("/auth/list/default/deny", test_authz_default_deny); + g_test_add_func("/auth/list/default/allow", test_authz_default_allow); + g_test_add_func("/auth/list/explicit/deny", test_authz_explicit_deny); + g_test_add_func("/auth/list/explicit/allow", test_authz_explicit_allow); + g_test_add_func("/auth/list/complex", test_authz_complex); + g_test_add_func("/auth/list/add-remove", test_authz_add_remove); + + return g_test_run(); +} diff --git a/tests/test-authz-listfile.c b/tests/test-authz-listfile.c new file mode 100644 index 0000000000..1e452fef6d --- /dev/null +++ b/tests/test-authz-listfile.c @@ -0,0 +1,195 @@ +/* + * QEMU list authorization object tests + * + * Copyright (c) 2018 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "qemu/osdep.h" +#include "qemu/main-loop.h" +#include "authz/listfile.h" + +static char *workdir; + +static gchar *qemu_authz_listfile_test_save(const gchar *name, + const gchar *cfg) +{ + gchar *path = g_strdup_printf("%s/default-deny.cfg", workdir); + GError *gerr = NULL; + + if (!g_file_set_contents(path, cfg, -1, &gerr)) { + g_printerr("Unable to save config %s: %s\n", + path, gerr->message); + g_error_free(gerr); + g_free(path); + rmdir(workdir); + abort(); + } + + return path; +} + +static void test_authz_default_deny(void) +{ + gchar *file = qemu_authz_listfile_test_save( + "default-deny.cfg", + "{ \"policy\": \"deny\" }"); + Error *local_err = NULL; + + QAuthZListFile *auth = qauthz_list_file_new("auth0", + file, false, + &local_err); + unlink(file); + g_free(file); + g_assert(local_err == NULL); + g_assert(!qauthz_is_allowed(QAUTHZ(auth), "fred", &error_abort)); + + object_unparent(OBJECT(auth)); +} + +static void test_authz_default_allow(void) +{ + gchar *file = qemu_authz_listfile_test_save( + "default-allow.cfg", + "{ \"policy\": \"allow\" }"); + Error *local_err = NULL; + + QAuthZListFile *auth = qauthz_list_file_new("auth0", + file, false, + &local_err); + unlink(file); + g_free(file); + g_assert(local_err == NULL); + g_assert(qauthz_is_allowed(QAUTHZ(auth), "fred", &error_abort)); + + object_unparent(OBJECT(auth)); +} + +static void test_authz_explicit_deny(void) +{ + gchar *file = qemu_authz_listfile_test_save( + "explicit-deny.cfg", + "{ \"rules\": [ " + " { \"match\": \"fred\"," + " \"policy\": \"deny\"," + " \"format\": \"exact\" } ]," + " \"policy\": \"allow\" }"); + Error *local_err = NULL; + + QAuthZListFile *auth = qauthz_list_file_new("auth0", + file, false, + &local_err); + unlink(file); + g_free(file); + g_assert(local_err == NULL); + + g_assert(!qauthz_is_allowed(QAUTHZ(auth), "fred", &error_abort)); + + object_unparent(OBJECT(auth)); +} + +static void test_authz_explicit_allow(void) +{ + gchar *file = qemu_authz_listfile_test_save( + "explicit-allow.cfg", + "{ \"rules\": [ " + " { \"match\": \"fred\"," + " \"policy\": \"allow\"," + " \"format\": \"exact\" } ]," + " \"policy\": \"deny\" }"); + Error *local_err = NULL; + + QAuthZListFile *auth = qauthz_list_file_new("auth0", + file, false, + &local_err); + unlink(file); + g_free(file); + g_assert(local_err == NULL); + + g_assert(qauthz_is_allowed(QAUTHZ(auth), "fred", &error_abort)); + + object_unparent(OBJECT(auth)); +} + + +static void test_authz_complex(void) +{ + gchar *file = qemu_authz_listfile_test_save( + "complex.cfg", + "{ \"rules\": [ " + " { \"match\": \"fred\"," + " \"policy\": \"allow\"," + " \"format\": \"exact\" }," + " { \"match\": \"bob\"," + " \"policy\": \"allow\"," + " \"format\": \"exact\" }," + " { \"match\": \"dan\"," + " \"policy\": \"deny\"," + " \"format\": \"exact\" }," + " { \"match\": \"dan*\"," + " \"policy\": \"allow\"," + " \"format\": \"glob\" } ]," + " \"policy\": \"deny\" }"); + + Error *local_err = NULL; + + QAuthZListFile *auth = qauthz_list_file_new("auth0", + file, false, + &local_err); + unlink(file); + g_free(file); + g_assert(local_err == NULL); + + g_assert(qauthz_is_allowed(QAUTHZ(auth), "fred", &error_abort)); + g_assert(qauthz_is_allowed(QAUTHZ(auth), "bob", &error_abort)); + g_assert(!qauthz_is_allowed(QAUTHZ(auth), "dan", &error_abort)); + g_assert(qauthz_is_allowed(QAUTHZ(auth), "danb", &error_abort)); + + object_unparent(OBJECT(auth)); +} + + +int main(int argc, char **argv) +{ + int ret; + GError *gerr = NULL; + + g_test_init(&argc, &argv, NULL); + + module_call_init(MODULE_INIT_QOM); + + workdir = g_dir_make_tmp("qemu-test-authz-listfile-XXXXXX", + &gerr); + if (!workdir) { + g_printerr("Unable to create temporary dir: %s\n", + gerr->message); + g_error_free(gerr); + abort(); + } + + g_test_add_func("/auth/list/default/deny", test_authz_default_deny); + g_test_add_func("/auth/list/default/allow", test_authz_default_allow); + g_test_add_func("/auth/list/explicit/deny", test_authz_explicit_deny); + g_test_add_func("/auth/list/explicit/allow", test_authz_explicit_allow); + g_test_add_func("/auth/list/complex", test_authz_complex); + + ret = g_test_run(); + + rmdir(workdir); + g_free(workdir); + + return ret; +} diff --git a/tests/test-authz-pam.c b/tests/test-authz-pam.c new file mode 100644 index 0000000000..93d5ac8bbf --- /dev/null +++ b/tests/test-authz-pam.c @@ -0,0 +1,124 @@ +/* + * QEMU PAM authorization object tests + * + * Copyright (c) 2018 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "authz/pamacct.h" + +#include <security/pam_appl.h> + +static bool failauth; + +/* + * These two functions are exported by libpam.so. + * + * By defining them again here, our impls are resolved + * by the linker instead of those in libpam.so + * + * The test suite is thus isolated from the host system + * PAM setup, so we can do predictable test scenarios + */ +int +pam_start(const char *service_name, const char *user, + const struct pam_conv *pam_conversation, + pam_handle_t **pamh) +{ + failauth = true; + if (!g_str_equal(service_name, "qemu-vnc")) { + return PAM_AUTH_ERR; + } + + if (g_str_equal(user, "fred")) { + failauth = false; + } + + return PAM_SUCCESS; +} + + +int +pam_acct_mgmt(pam_handle_t *pamh, int flags) +{ + if (failauth) { + return PAM_AUTH_ERR; + } + + return PAM_SUCCESS; +} + + +static void test_authz_unknown_service(void) +{ + Error *local_err = NULL; + QAuthZPAM *auth = qauthz_pam_new("auth0", + "qemu-does-not-exist", + &error_abort); + + g_assert_nonnull(auth); + + g_assert_false(qauthz_is_allowed(QAUTHZ(auth), "fred", &local_err)); + + error_free_or_abort(&local_err); + object_unparent(OBJECT(auth)); +} + + +static void test_authz_good_user(void) +{ + QAuthZPAM *auth = qauthz_pam_new("auth0", + "qemu-vnc", + &error_abort); + + g_assert_nonnull(auth); + + g_assert_true(qauthz_is_allowed(QAUTHZ(auth), "fred", &error_abort)); + + object_unparent(OBJECT(auth)); +} + + +static void test_authz_bad_user(void) +{ + Error *local_err = NULL; + QAuthZPAM *auth = qauthz_pam_new("auth0", + "qemu-vnc", + &error_abort); + + g_assert_nonnull(auth); + + g_assert_false(qauthz_is_allowed(QAUTHZ(auth), "bob", &local_err)); + + error_free_or_abort(&local_err); + object_unparent(OBJECT(auth)); +} + + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + module_call_init(MODULE_INIT_QOM); + + g_test_add_func("/auth/pam/unknown-service", test_authz_unknown_service); + g_test_add_func("/auth/pam/good-user", test_authz_good_user); + g_test_add_func("/auth/pam/bad-user", test_authz_bad_user); + + return g_test_run(); +} diff --git a/tests/test-authz-simple.c b/tests/test-authz-simple.c new file mode 100644 index 0000000000..2cf14fb87e --- /dev/null +++ b/tests/test-authz-simple.c @@ -0,0 +1,50 @@ +/* + * QEMU simple authorization object testing + * + * Copyright (c) 2018 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" + +#include "authz/simple.h" + + +static void test_authz_simple(void) +{ + QAuthZSimple *authz = qauthz_simple_new("authz0", + "cthulu", + &error_abort); + + g_assert(!qauthz_is_allowed(QAUTHZ(authz), "cthul", &error_abort)); + g_assert(qauthz_is_allowed(QAUTHZ(authz), "cthulu", &error_abort)); + g_assert(!qauthz_is_allowed(QAUTHZ(authz), "cthuluu", &error_abort)); + g_assert(!qauthz_is_allowed(QAUTHZ(authz), "fred", &error_abort)); + + object_unparent(OBJECT(authz)); +} + + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + module_call_init(MODULE_INIT_QOM); + + g_test_add_func("/authz/simple", test_authz_simple); + + return g_test_run(); +} diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c index 821be405f0..eda90750eb 100644 --- a/tests/test-bdrv-drain.c +++ b/tests/test-bdrv-drain.c @@ -1501,6 +1501,36 @@ static void test_append_to_drained(void) blk_unref(blk); } +static void test_set_aio_context(void) +{ + BlockDriverState *bs; + IOThread *a = iothread_new(); + IOThread *b = iothread_new(); + AioContext *ctx_a = iothread_get_aio_context(a); + AioContext *ctx_b = iothread_get_aio_context(b); + + bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR, + &error_abort); + + bdrv_drained_begin(bs); + bdrv_set_aio_context(bs, ctx_a); + + aio_context_acquire(ctx_a); + bdrv_drained_end(bs); + + bdrv_drained_begin(bs); + bdrv_set_aio_context(bs, ctx_b); + aio_context_release(ctx_a); + aio_context_acquire(ctx_b); + bdrv_set_aio_context(bs, qemu_get_aio_context()); + aio_context_release(ctx_b); + bdrv_drained_end(bs); + + bdrv_unref(bs); + iothread_join(a); + iothread_join(b); +} + int main(int argc, char **argv) { int ret; @@ -1582,6 +1612,8 @@ int main(int argc, char **argv) g_test_add_func("/bdrv-drain/attach/drain", test_append_to_drained); + g_test_add_func("/bdrv-drain/set_aio_context", test_set_aio_context); + ret = g_test_run(); qemu_event_destroy(&done_event); return ret; diff --git a/tests/test-bdrv-graph-mod.c b/tests/test-bdrv-graph-mod.c new file mode 100644 index 0000000000..458dfa6661 --- /dev/null +++ b/tests/test-bdrv-graph-mod.c @@ -0,0 +1,198 @@ +/* + * Block node graph modifications tests + * + * Copyright (c) 2019 Virtuozzo International GmbH. All rights reserved. + * + * 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/>. + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "block/block_int.h" +#include "sysemu/block-backend.h" + +static BlockDriver bdrv_pass_through = { + .format_name = "pass-through", + .bdrv_child_perm = bdrv_filter_default_perms, +}; + +static void no_perm_default_perms(BlockDriverState *bs, BdrvChild *c, + const BdrvChildRole *role, + BlockReopenQueue *reopen_queue, + uint64_t perm, uint64_t shared, + uint64_t *nperm, uint64_t *nshared) +{ + *nperm = 0; + *nshared = BLK_PERM_ALL; +} + +static BlockDriver bdrv_no_perm = { + .format_name = "no-perm", + .bdrv_child_perm = no_perm_default_perms, +}; + +static BlockDriverState *no_perm_node(const char *name) +{ + return bdrv_new_open_driver(&bdrv_no_perm, name, BDRV_O_RDWR, &error_abort); +} + +static BlockDriverState *pass_through_node(const char *name) +{ + return bdrv_new_open_driver(&bdrv_pass_through, name, + BDRV_O_RDWR, &error_abort); +} + +/* + * test_update_perm_tree + * + * When checking node for a possibility to update permissions, it's subtree + * should be correctly checked too. New permissions for each node should be + * calculated and checked in context of permissions of other nodes. If we + * check new permissions of the node only in context of old permissions of + * its neighbors, we can finish up with wrong permission graph. + * + * This test firstly create the following graph: + * +--------+ + * | root | + * +--------+ + * | + * | perm: write, read + * | shared: except write + * v + * +-------------------+ +----------------+ + * | passtrough filter |---------->| null-co node | + * +-------------------+ +----------------+ + * + * + * and then, tries to append filter under node. Expected behavior: fail. + * Otherwise we'll get the following picture, with two BdrvChild'ren, having + * write permission to one node, without actually sharing it. + * + * +--------+ + * | root | + * +--------+ + * | + * | perm: write, read + * | shared: except write + * v + * +-------------------+ + * | passtrough filter | + * +-------------------+ + * | | + * perm: write, read | | perm: write, read + * shared: except write | | shared: except write + * v v + * +----------------+ + * | null co node | + * +----------------+ + */ +static void test_update_perm_tree(void) +{ + Error *local_err = NULL; + + BlockBackend *root = blk_new(BLK_PERM_WRITE | BLK_PERM_CONSISTENT_READ, + BLK_PERM_ALL & ~BLK_PERM_WRITE); + BlockDriverState *bs = no_perm_node("node"); + BlockDriverState *filter = pass_through_node("filter"); + + blk_insert_bs(root, bs, &error_abort); + + bdrv_attach_child(filter, bs, "child", &child_file, &error_abort); + + bdrv_append(filter, bs, &local_err); + + g_assert_nonnull(local_err); + + bdrv_unref(bs); + blk_unref(root); +} + +/* + * test_should_update_child + * + * Test that bdrv_replace_node, and concretely should_update_child + * do the right thing, i.e. not creating loops on the graph. + * + * The test does the following: + * 1. initial graph: + * + * +------+ +--------+ + * | root | | filter | + * +------+ +--------+ + * | | + * root| target| + * v v + * +------+ +--------+ + * | node |<---------| target | + * +------+ backing +--------+ + * + * 2. Append @filter above @node. If should_update_child works correctly, + * it understands, that backing child of @target should not be updated, + * as it will create a loop on node graph. Resulting picture should + * be the left one, not the right: + * + * +------+ +------+ + * | root | | root | + * +------+ +------+ + * | | + * root| root| + * v v + * +--------+ target +--------+ target + * | filter |--------------+ | filter |--------------+ + * +--------+ | +--------+ | + * | | | ^ v + * backing| | backing| | +--------+ + * v v | +-----------| target | + * +------+ +--------+ v backing +--------+ + * | node |<---------| target | +------+ + * +------+ backing +--------+ | node | + * +------+ + * + * (good picture) (bad picture) + * + */ +static void test_should_update_child(void) +{ + BlockBackend *root = blk_new(0, BLK_PERM_ALL); + BlockDriverState *bs = no_perm_node("node"); + BlockDriverState *filter = no_perm_node("filter"); + BlockDriverState *target = no_perm_node("target"); + + blk_insert_bs(root, bs, &error_abort); + + bdrv_set_backing_hd(target, bs, &error_abort); + + g_assert(target->backing->bs == bs); + bdrv_attach_child(filter, target, "target", &child_file, &error_abort); + bdrv_append(filter, bs, &error_abort); + g_assert(target->backing->bs == bs); + + bdrv_unref(bs); + blk_unref(root); +} + +int main(int argc, char *argv[]) +{ + bdrv_init(); + qemu_init_main_loop(&error_abort); + + g_test_init(&argc, &argv, NULL); + + g_test_add_func("/bdrv-graph-mod/update-perm-tree", test_update_perm_tree); + g_test_add_func("/bdrv-graph-mod/should-update-child", + test_should_update_child); + + return g_test_run(); +} diff --git a/tests/test-crypto-tlssession.c b/tests/test-crypto-tlssession.c index 6fa9950afb..15212ec276 100644 --- a/tests/test-crypto-tlssession.c +++ b/tests/test-crypto-tlssession.c @@ -28,7 +28,7 @@ #include "qom/object_interfaces.h" #include "qapi/error.h" #include "qemu/sockets.h" -#include "qemu/acl.h" +#include "authz/list.h" #ifdef QCRYPTO_HAVE_TLS_TEST_SUPPORT @@ -229,7 +229,7 @@ static void test_crypto_tls_session_x509(const void *opaque) QCryptoTLSCreds *serverCreds; QCryptoTLSSession *clientSess = NULL; QCryptoTLSSession *serverSess = NULL; - qemu_acl *acl; + QAuthZList *auth; const char * const *wildcards; int channel[2]; bool clientShake = false; @@ -285,11 +285,15 @@ static void test_crypto_tls_session_x509(const void *opaque) SERVER_CERT_DIR); g_assert(serverCreds != NULL); - acl = qemu_acl_init("tlssessionacl"); - qemu_acl_reset(acl); + auth = qauthz_list_new("tlssessionacl", + QAUTHZ_LIST_POLICY_DENY, + &error_abort); wildcards = data->wildcards; while (wildcards && *wildcards) { - qemu_acl_append(acl, 0, *wildcards); + qauthz_list_append_rule(auth, *wildcards, + QAUTHZ_LIST_POLICY_ALLOW, + QAUTHZ_LIST_FORMAT_GLOB, + &error_abort); wildcards++; } @@ -377,6 +381,7 @@ static void test_crypto_tls_session_x509(const void *opaque) object_unparent(OBJECT(serverCreds)); object_unparent(OBJECT(clientCreds)); + object_unparent(OBJECT(auth)); qcrypto_tls_session_free(serverSess); qcrypto_tls_session_free(clientSess); diff --git a/tests/test-io-channel-tls.c b/tests/test-io-channel-tls.c index 4900c6d433..43b707eba7 100644 --- a/tests/test-io-channel-tls.c +++ b/tests/test-io-channel-tls.c @@ -29,8 +29,8 @@ #include "io-channel-helpers.h" #include "crypto/init.h" #include "crypto/tlscredsx509.h" -#include "qemu/acl.h" #include "qapi/error.h" +#include "authz/list.h" #include "qom/object_interfaces.h" #ifdef QCRYPTO_HAVE_TLS_TEST_SUPPORT @@ -113,7 +113,7 @@ static void test_io_channel_tls(const void *opaque) QIOChannelTLS *serverChanTLS; QIOChannelSocket *clientChanSock; QIOChannelSocket *serverChanSock; - qemu_acl *acl; + QAuthZList *auth; const char * const *wildcards; int channel[2]; struct QIOChannelTLSHandshakeData clientHandshake = { false, false }; @@ -161,11 +161,15 @@ static void test_io_channel_tls(const void *opaque) SERVER_CERT_DIR); g_assert(serverCreds != NULL); - acl = qemu_acl_init("channeltlsacl"); - qemu_acl_reset(acl); + auth = qauthz_list_new("channeltlsacl", + QAUTHZ_LIST_POLICY_DENY, + &error_abort); wildcards = data->wildcards; while (wildcards && *wildcards) { - qemu_acl_append(acl, 0, *wildcards); + qauthz_list_append_rule(auth, *wildcards, + QAUTHZ_LIST_POLICY_ALLOW, + QAUTHZ_LIST_FORMAT_GLOB, + &error_abort); wildcards++; } @@ -253,6 +257,8 @@ static void test_io_channel_tls(const void *opaque) object_unref(OBJECT(serverChanSock)); object_unref(OBJECT(clientChanSock)); + object_unparent(OBJECT(auth)); + close(channel[0]); close(channel[1]); } diff --git a/tests/test-util-filemonitor.c b/tests/test-util-filemonitor.c new file mode 100644 index 0000000000..5d95cea5ee --- /dev/null +++ b/tests/test-util-filemonitor.c @@ -0,0 +1,685 @@ +/* + * Tests for util/filemonitor-*.c + * + * Copyright 2018 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 library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "qemu/osdep.h" +#include "qemu/main-loop.h" +#include "qapi/error.h" +#include "qemu/filemonitor.h" + +#include <utime.h> + +enum { + QFILE_MONITOR_TEST_OP_CREATE, + QFILE_MONITOR_TEST_OP_APPEND, + QFILE_MONITOR_TEST_OP_TRUNC, + QFILE_MONITOR_TEST_OP_RENAME, + QFILE_MONITOR_TEST_OP_TOUCH, + QFILE_MONITOR_TEST_OP_UNLINK, +}; + +typedef struct { + int type; + const char *filesrc; + const char *filedst; +} QFileMonitorTestOp; + +typedef struct { + const char *file; +} QFileMonitorTestWatch; + +typedef struct { + gsize nwatches; + const QFileMonitorTestWatch *watches; + + gsize nops; + const QFileMonitorTestOp *ops; +} QFileMonitorTestPlan; + +typedef struct { + int id; + QFileMonitorEvent event; + char *filename; +} QFileMonitorTestRecord; + + +typedef struct { + QemuMutex lock; + GList *records; +} QFileMonitorTestData; + +static QemuMutex evlock; +static bool evstopping; +static bool evrunning; + +/* + * Main function for a background thread that is + * running the event loop during the test + */ +static void * +qemu_file_monitor_test_event_loop(void *opaque G_GNUC_UNUSED) +{ + qemu_mutex_lock(&evlock); + + while (!evstopping) { + qemu_mutex_unlock(&evlock); + main_loop_wait(true); + qemu_mutex_lock(&evlock); + } + + evrunning = false; + qemu_mutex_unlock(&evlock); + return NULL; +} + + +/* + * File monitor event handler which simply maintains + * an ordered list of all events that it receives + */ +static void +qemu_file_monitor_test_handler(int id, + QFileMonitorEvent event, + const char *filename, + void *opaque) +{ + QFileMonitorTestData *data = opaque; + QFileMonitorTestRecord *rec = g_new0(QFileMonitorTestRecord, 1); + + rec->id = id; + rec->event = event; + rec->filename = g_strdup(filename); + + qemu_mutex_lock(&data->lock); + data->records = g_list_append(data->records, rec); + qemu_mutex_unlock(&data->lock); +} + + +static void +qemu_file_monitor_test_record_free(QFileMonitorTestRecord *rec) +{ + g_free(rec->filename); + g_free(rec); +} + + +/* + * Get the next event record that has been received by + * the file monitor event handler. Since events are + * emitted in the background thread running the event + * loop, we can't assume there is a record available + * immediately. Thus we will sleep for upto 5 seconds + * to wait for the event to be queued for us. + */ +static QFileMonitorTestRecord * +qemu_file_monitor_test_next_record(QFileMonitorTestData *data) +{ + GTimer *timer = g_timer_new(); + QFileMonitorTestRecord *record = NULL; + GList *tmp; + + qemu_mutex_lock(&data->lock); + while (!data->records && g_timer_elapsed(timer, NULL) < 5) { + qemu_mutex_unlock(&data->lock); + usleep(10 * 1000); + qemu_mutex_lock(&data->lock); + } + if (data->records) { + record = data->records->data; + tmp = data->records; + data->records = g_list_remove_link(data->records, tmp); + g_list_free(tmp); + } + qemu_mutex_unlock(&data->lock); + + g_timer_destroy(timer); + return record; +} + + +/* + * Check whether the event record we retrieved matches + * data we were expecting to see for the event + */ +static bool +qemu_file_monitor_test_expect(QFileMonitorTestData *data, + int id, + QFileMonitorEvent event, + const char *filename) +{ + QFileMonitorTestRecord *rec; + bool ret = false; + + rec = qemu_file_monitor_test_next_record(data); + + if (!rec) { + g_printerr("Missing event watch id %d event %d file %s\n", + id, event, filename); + return false; + } + + if (id != rec->id) { + g_printerr("Expected watch id %d but got %d\n", id, rec->id); + goto cleanup; + } + + if (event != rec->event) { + g_printerr("Expected event %d but got %d\n", event, rec->event); + goto cleanup; + } + + if (!g_str_equal(filename, rec->filename)) { + g_printerr("Expected filename %s but got %s\n", + filename, rec->filename); + goto cleanup; + } + + ret = true; + + cleanup: + qemu_file_monitor_test_record_free(rec); + return ret; +} + + +static void +test_file_monitor_events(const void *opaque) +{ + const QFileMonitorTestPlan *plan = opaque; + Error *local_err = NULL; + GError *gerr = NULL; + QFileMonitor *mon = qemu_file_monitor_new(&local_err); + QemuThread th; + GTimer *timer; + gchar *dir = NULL; + int err = -1; + gsize i, j; + char *pathsrc = NULL; + char *pathdst = NULL; + QFileMonitorTestData data; + + qemu_mutex_init(&data.lock); + data.records = NULL; + + /* + * The file monitor needs the main loop running in + * order to receive events from inotify. We must + * thus spawn a background thread to run an event + * loop impl, while this thread triggers the + * actual file operations we're testing + */ + evrunning = 1; + evstopping = 0; + qemu_thread_create(&th, "event-loop", + qemu_file_monitor_test_event_loop, NULL, + QEMU_THREAD_JOINABLE); + + if (local_err) { + g_printerr("File monitoring not available: %s", + error_get_pretty(local_err)); + error_free(local_err); + return; + } + + dir = g_dir_make_tmp("test-util-filemonitor-XXXXXX", + &gerr); + if (!dir) { + g_printerr("Unable to create tmp dir %s", + gerr->message); + g_error_free(gerr); + abort(); + } + + /* + * First register all the directory / file watches + * we're interested in seeing events against + */ + for (i = 0; i < plan->nwatches; i++) { + int watchid; + watchid = qemu_file_monitor_add_watch(mon, + dir, + plan->watches[i].file, + qemu_file_monitor_test_handler, + &data, + &local_err); + if (watchid < 0) { + g_printerr("Unable to add watch %s", + error_get_pretty(local_err)); + goto cleanup; + } + } + + + /* + * Now invoke all the file operations (create, + * delete, rename, chmod, etc). These operations + * will trigger the various file monitor events + */ + for (i = 0; i < plan->nops; i++) { + const QFileMonitorTestOp *op = &(plan->ops[i]); + int fd; + struct utimbuf ubuf; + + pathsrc = g_strdup_printf("%s/%s", dir, op->filesrc); + if (op->filedst) { + pathdst = g_strdup_printf("%s/%s", dir, op->filedst); + } + + switch (op->type) { + case QFILE_MONITOR_TEST_OP_CREATE: + fd = open(pathsrc, O_WRONLY | O_CREAT, 0700); + if (fd < 0) { + g_printerr("Unable to create %s: %s", + pathsrc, strerror(errno)); + goto cleanup; + } + close(fd); + break; + + case QFILE_MONITOR_TEST_OP_APPEND: + fd = open(pathsrc, O_WRONLY | O_APPEND, 0700); + if (fd < 0) { + g_printerr("Unable to open %s: %s", + pathsrc, strerror(errno)); + goto cleanup; + } + + if (write(fd, "Hello World", 10) != 10) { + g_printerr("Unable to write %s: %s", + pathsrc, strerror(errno)); + close(fd); + goto cleanup; + } + close(fd); + break; + + case QFILE_MONITOR_TEST_OP_TRUNC: + if (truncate(pathsrc, 4) < 0) { + g_printerr("Unable to truncate %s: %s", + pathsrc, strerror(errno)); + goto cleanup; + } + break; + + case QFILE_MONITOR_TEST_OP_RENAME: + if (rename(pathsrc, pathdst) < 0) { + g_printerr("Unable to rename %s to %s: %s", + pathsrc, pathdst, strerror(errno)); + goto cleanup; + } + break; + + case QFILE_MONITOR_TEST_OP_UNLINK: + if (unlink(pathsrc) < 0) { + g_printerr("Unable to unlink %s: %s", + pathsrc, strerror(errno)); + goto cleanup; + } + break; + + case QFILE_MONITOR_TEST_OP_TOUCH: + ubuf.actime = 1024; + ubuf.modtime = 1025; + if (utime(pathsrc, &ubuf) < 0) { + g_printerr("Unable to touch %s: %s", + pathsrc, strerror(errno)); + goto cleanup; + } + break; + + default: + g_assert_not_reached(); + } + + g_free(pathsrc); + g_free(pathdst); + pathsrc = pathdst = NULL; + } + + + /* + * Finally validate that we have received all the events + * we expect to see for the combination of watches and + * file operations + */ + for (i = 0; i < plan->nops; i++) { + const QFileMonitorTestOp *op = &(plan->ops[i]); + + switch (op->type) { + case QFILE_MONITOR_TEST_OP_CREATE: + for (j = 0; j < plan->nwatches; j++) { + if (plan->watches[j].file && + !g_str_equal(plan->watches[j].file, op->filesrc)) + continue; + + if (!qemu_file_monitor_test_expect( + &data, j, QFILE_MONITOR_EVENT_CREATED, op->filesrc)) + goto cleanup; + } + break; + + case QFILE_MONITOR_TEST_OP_APPEND: + case QFILE_MONITOR_TEST_OP_TRUNC: + for (j = 0; j < plan->nwatches; j++) { + if (plan->watches[j].file && + !g_str_equal(plan->watches[j].file, op->filesrc)) + continue; + + if (!qemu_file_monitor_test_expect( + &data, j, QFILE_MONITOR_EVENT_MODIFIED, op->filesrc)) + goto cleanup; + } + break; + + case QFILE_MONITOR_TEST_OP_RENAME: + for (j = 0; j < plan->nwatches; j++) { + if (plan->watches[j].file && + !g_str_equal(plan->watches[j].file, op->filesrc)) + continue; + + if (!qemu_file_monitor_test_expect( + &data, j, QFILE_MONITOR_EVENT_DELETED, op->filesrc)) + goto cleanup; + } + + for (j = 0; j < plan->nwatches; j++) { + if (plan->watches[j].file && + !g_str_equal(plan->watches[j].file, op->filedst)) + continue; + + if (!qemu_file_monitor_test_expect( + &data, j, QFILE_MONITOR_EVENT_CREATED, op->filedst)) + goto cleanup; + } + break; + + case QFILE_MONITOR_TEST_OP_TOUCH: + for (j = 0; j < plan->nwatches; j++) { + if (plan->watches[j].file && + !g_str_equal(plan->watches[j].file, op->filesrc)) + continue; + + if (!qemu_file_monitor_test_expect( + &data, j, QFILE_MONITOR_EVENT_ATTRIBUTES, op->filesrc)) + goto cleanup; + } + break; + + case QFILE_MONITOR_TEST_OP_UNLINK: + for (j = 0; j < plan->nwatches; j++) { + if (plan->watches[j].file && + !g_str_equal(plan->watches[j].file, op->filesrc)) + continue; + + if (!qemu_file_monitor_test_expect( + &data, j, QFILE_MONITOR_EVENT_DELETED, op->filesrc)) + goto cleanup; + } + break; + + default: + g_assert_not_reached(); + } + } + + err = 0; + + cleanup: + g_free(pathsrc); + g_free(pathdst); + + qemu_mutex_lock(&evlock); + evstopping = 1; + timer = g_timer_new(); + while (evrunning && g_timer_elapsed(timer, NULL) < 5) { + qemu_mutex_unlock(&evlock); + usleep(10 * 1000); + qemu_mutex_lock(&evlock); + } + qemu_mutex_unlock(&evlock); + + if (g_timer_elapsed(timer, NULL) >= 5) { + g_printerr("Event loop failed to quit after 5 seconds\n"); + } + g_timer_destroy(timer); + + for (i = 0; i < plan->nops; i++) { + const QFileMonitorTestOp *op = &(plan->ops[i]); + pathsrc = g_strdup_printf("%s/%s", dir, op->filesrc); + unlink(pathsrc); + g_free(pathsrc); + if (op->filedst) { + pathdst = g_strdup_printf("%s/%s", dir, op->filedst); + unlink(pathdst); + g_free(pathdst); + } + } + + qemu_file_monitor_free(mon); + g_list_foreach(data.records, + (GFunc)qemu_file_monitor_test_record_free, NULL); + g_list_free(data.records); + qemu_mutex_destroy(&data.lock); + if (dir) { + rmdir(dir); + } + g_free(dir); + g_assert(err == 0); +} + + +/* + * Set of structs which define which file name patterns + * we're trying to watch against. NULL, means all files + * in the directory + */ +static const QFileMonitorTestWatch watches_any[] = { + { NULL }, +}; + +static const QFileMonitorTestWatch watches_one[] = { + { "one.txt" }, +}; + +static const QFileMonitorTestWatch watches_two[] = { + { "two.txt" }, +}; + +static const QFileMonitorTestWatch watches_many[] = { + { NULL }, + { "one.txt" }, + { "two.txt" }, +}; + + +/* + * Various sets of file operations we're going to + * trigger and validate events for + */ +static const QFileMonitorTestOp ops_create_one[] = { + { .type = QFILE_MONITOR_TEST_OP_CREATE, + .filesrc = "one.txt", } +}; + +static const QFileMonitorTestOp ops_delete_one[] = { + { .type = QFILE_MONITOR_TEST_OP_CREATE, + .filesrc = "one.txt", }, + { .type = QFILE_MONITOR_TEST_OP_UNLINK, + .filesrc = "one.txt", } +}; + +static const QFileMonitorTestOp ops_create_many[] = { + { .type = QFILE_MONITOR_TEST_OP_CREATE, + .filesrc = "one.txt", }, + { .type = QFILE_MONITOR_TEST_OP_CREATE, + .filesrc = "two.txt", }, + { .type = QFILE_MONITOR_TEST_OP_CREATE, + .filesrc = "three.txt", } +}; + +static const QFileMonitorTestOp ops_rename_one[] = { + { .type = QFILE_MONITOR_TEST_OP_CREATE, + .filesrc = "one.txt", }, + { .type = QFILE_MONITOR_TEST_OP_RENAME, + .filesrc = "one.txt", .filedst = "two.txt" } +}; + +static const QFileMonitorTestOp ops_rename_many[] = { + { .type = QFILE_MONITOR_TEST_OP_CREATE, + .filesrc = "one.txt", }, + { .type = QFILE_MONITOR_TEST_OP_CREATE, + .filesrc = "two.txt", }, + { .type = QFILE_MONITOR_TEST_OP_RENAME, + .filesrc = "one.txt", .filedst = "two.txt" } +}; + +static const QFileMonitorTestOp ops_append_one[] = { + { .type = QFILE_MONITOR_TEST_OP_CREATE, + .filesrc = "one.txt", }, + { .type = QFILE_MONITOR_TEST_OP_APPEND, + .filesrc = "one.txt", }, +}; + +static const QFileMonitorTestOp ops_trunc_one[] = { + { .type = QFILE_MONITOR_TEST_OP_CREATE, + .filesrc = "one.txt", }, + { .type = QFILE_MONITOR_TEST_OP_TRUNC, + .filesrc = "one.txt", }, +}; + +static const QFileMonitorTestOp ops_touch_one[] = { + { .type = QFILE_MONITOR_TEST_OP_CREATE, + .filesrc = "one.txt", }, + { .type = QFILE_MONITOR_TEST_OP_TOUCH, + .filesrc = "one.txt", }, +}; + + +/* + * No we define data sets for the combinatorial + * expansion of file watches and operation sets + */ +#define PLAN_DATA(o, w) \ + static const QFileMonitorTestPlan plan_ ## o ## _ ## w = { \ + .nops = G_N_ELEMENTS(ops_ ##o), \ + .ops = ops_ ##o, \ + .nwatches = G_N_ELEMENTS(watches_ ##w), \ + .watches = watches_ ## w, \ + } + +PLAN_DATA(create_one, any); +PLAN_DATA(create_one, one); +PLAN_DATA(create_one, two); +PLAN_DATA(create_one, many); + +PLAN_DATA(delete_one, any); +PLAN_DATA(delete_one, one); +PLAN_DATA(delete_one, two); +PLAN_DATA(delete_one, many); + +PLAN_DATA(create_many, any); +PLAN_DATA(create_many, one); +PLAN_DATA(create_many, two); +PLAN_DATA(create_many, many); + +PLAN_DATA(rename_one, any); +PLAN_DATA(rename_one, one); +PLAN_DATA(rename_one, two); +PLAN_DATA(rename_one, many); + +PLAN_DATA(rename_many, any); +PLAN_DATA(rename_many, one); +PLAN_DATA(rename_many, two); +PLAN_DATA(rename_many, many); + +PLAN_DATA(append_one, any); +PLAN_DATA(append_one, one); +PLAN_DATA(append_one, two); +PLAN_DATA(append_one, many); + +PLAN_DATA(trunc_one, any); +PLAN_DATA(trunc_one, one); +PLAN_DATA(trunc_one, two); +PLAN_DATA(trunc_one, many); + +PLAN_DATA(touch_one, any); +PLAN_DATA(touch_one, one); +PLAN_DATA(touch_one, two); +PLAN_DATA(touch_one, many); + + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + qemu_init_main_loop(&error_abort); + + qemu_mutex_init(&evlock); + + /* + * Register test cases for the combinatorial + * expansion of file watches and operation sets + */ + #define PLAN_REGISTER(o, w) \ + g_test_add_data_func("/util/filemonitor/" # o "/" # w, \ + &plan_ ## o ## _ ## w, test_file_monitor_events) + + PLAN_REGISTER(create_one, any); + PLAN_REGISTER(create_one, one); + PLAN_REGISTER(create_one, two); + PLAN_REGISTER(create_one, many); + + PLAN_REGISTER(delete_one, any); + PLAN_REGISTER(delete_one, one); + PLAN_REGISTER(delete_one, two); + PLAN_REGISTER(delete_one, many); + + PLAN_REGISTER(create_many, any); + PLAN_REGISTER(create_many, one); + PLAN_REGISTER(create_many, two); + PLAN_REGISTER(create_many, many); + + PLAN_REGISTER(rename_one, any); + PLAN_REGISTER(rename_one, one); + PLAN_REGISTER(rename_one, two); + PLAN_REGISTER(rename_one, many); + + PLAN_REGISTER(rename_many, any); + PLAN_REGISTER(rename_many, one); + PLAN_REGISTER(rename_many, two); + PLAN_REGISTER(rename_many, many); + + PLAN_REGISTER(append_one, any); + PLAN_REGISTER(append_one, one); + PLAN_REGISTER(append_one, two); + PLAN_REGISTER(append_one, many); + + PLAN_REGISTER(trunc_one, any); + PLAN_REGISTER(trunc_one, one); + PLAN_REGISTER(trunc_one, two); + PLAN_REGISTER(trunc_one, many); + + PLAN_REGISTER(touch_one, any); + PLAN_REGISTER(touch_one, one); + PLAN_REGISTER(touch_one, two); + PLAN_REGISTER(touch_one, many); + + return g_test_run(); +} |