diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2021-01-28 12:30:30 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2021-01-28 12:30:30 +0000 |
commit | 0bcd12fb1513bad44f05f2d3a8eef2a99b3077b6 (patch) | |
tree | f3649aab45324e1d448b67a7dc1139edf7919374 | |
parent | 091f255b89e818b84cd003c1da552b6dc3fe3cbd (diff) | |
parent | a44be0334beae3a9affb4a3a92cc6852993d7a84 (diff) |
Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging
Block layer patches:
- Fix crash on write to read-only devices
- iotests: Rewrite 'check' in Python, get rid of 'groups' and allow
non-numeric test case names
# gpg: Signature made Wed 27 Jan 2021 19:56:00 GMT
# gpg: using RSA key DC3DEB159A9AF95D3D7456FE7F09B272C88F2FD6
# gpg: issuer "kwolf@redhat.com"
# gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" [full]
# Primary key fingerprint: DC3D EB15 9A9A F95D 3D74 56FE 7F09 B272 C88F 2FD6
* remotes/kevin/tags/for-upstream:
iotests: rename and move 169 and 199 tests
iotests: rewrite check into python
iotests: add testrunner.py
iotests: add testenv.py
iotests: add findtests.py
iotests: 146: drop extra whitespaces from .out file
virtio-scsi-test: Test writing to scsi-cd device
block: Separate blk_is_writable() and blk_supports_write_perm()
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
37 files changed, 1481 insertions, 1729 deletions
@@ -236,7 +236,6 @@ distclean: clean rm -f config-host.mak config-host.h* rm -f tests/tcg/config-*.mak rm -f config-all-disas.mak config.status - rm -f tests/qemu-iotests/common.env rm -f roms/seabios/config.mak roms/vgabios/config.mak rm -f qemu-plugins-ld.symbols qemu-plugins-ld64.symbols rm -f *-config-target.h *-config-devices.mak *-config-devices.h diff --git a/block/block-backend.c b/block/block-backend.c index ce78d30794..e493f17515 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -1826,17 +1826,30 @@ void blk_error_action(BlockBackend *blk, BlockErrorAction action, } } -bool blk_is_read_only(BlockBackend *blk) +/* + * Returns true if the BlockBackend can support taking write permissions + * (because its root node is not read-only). + */ +bool blk_supports_write_perm(BlockBackend *blk) { BlockDriverState *bs = blk_bs(blk); if (bs) { - return bdrv_is_read_only(bs); + return !bdrv_is_read_only(bs); } else { - return blk->root_state.read_only; + return !blk->root_state.read_only; } } +/* + * Returns true if the BlockBackend can be written to in its current + * configuration (i.e. if write permission have been requested) + */ +bool blk_is_writable(BlockBackend *blk) +{ + return blk->perm & BLK_PERM_WRITE; +} + bool blk_is_sg(BlockBackend *blk) { BlockDriverState *bs = blk_bs(blk); diff --git a/docs/devel/testing.rst b/docs/devel/testing.rst index 9f8b77c8ec..809af69725 100644 --- a/docs/devel/testing.rst +++ b/docs/devel/testing.rst @@ -111,7 +111,7 @@ check-block ----------- ``make check-block`` runs a subset of the block layer iotests (the tests that -are in the "auto" group in ``tests/qemu-iotests/group``). +are in the "auto" group). See the "QEMU iotests" section below for more information. GCC gcov support @@ -224,6 +224,54 @@ another application on the host may have locked the file, possibly leading to a test failure. If using such devices are explicitly desired, consider adding ``locking=off`` option to disable image locking. +Test case groups +---------------- + +"Tests may belong to one or more test groups, which are defined in the form +of a comment in the test source file. By convention, test groups are listed +in the second line of the test file, after the "#!/..." line, like this: + +.. code:: + + #!/usr/bin/env python3 + # group: auto quick + # + ... + +Another way of defining groups is creating the tests/qemu-iotests/group.local +file. This should be used only for downstream (this file should never appear +in upstream). This file may be used for defining some downstream test groups +or for temporarily disabling tests, like this: + +.. code:: + + # groups for some company downstream process + # + # ci - tests to run on build + # down - our downstream tests, not for upstream + # + # Format of each line is: + # TEST_NAME TEST_GROUP [TEST_GROUP ]... + + 013 ci + 210 disabled + 215 disabled + our-ugly-workaround-test down ci + +Note that the following group names have a special meaning: + +- quick: Tests in this group should finish within a few seconds. + +- auto: Tests in this group are used during "make check" and should be + runnable in any case. That means they should run with every QEMU binary + (also non-x86), with every QEMU configuration (i.e. must not fail if + an optional feature is not compiled in - but reporting a "skip" is ok), + work at least with the qcow2 file format, work with all kind of host + filesystems and users (e.g. "nobody" or "root") and must not take too + much memory and disk space (since CI pipelines tend to fail otherwise). + +- disabled: Tests in this group are disabled and ignored by check. + .. _docker-ref: Docker based tests diff --git a/hw/block/dataplane/xen-block.c b/hw/block/dataplane/xen-block.c index 3675f8deaf..860787580a 100644 --- a/hw/block/dataplane/xen-block.c +++ b/hw/block/dataplane/xen-block.c @@ -168,7 +168,7 @@ static int xen_block_parse_request(XenBlockRequest *request) }; if (request->req.operation != BLKIF_OP_READ && - blk_is_read_only(dataplane->blk)) { + !blk_is_writable(dataplane->blk)) { error_report("error: write req for ro device"); goto err; } diff --git a/hw/block/fdc.c b/hw/block/fdc.c index 3636874432..292ea87805 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -444,7 +444,7 @@ static void fd_revalidate(FDrive *drv) FLOPPY_DPRINTF("revalidate\n"); if (drv->blk != NULL) { - drv->ro = blk_is_read_only(drv->blk); + drv->ro = !blk_is_writable(drv->blk); if (!blk_is_inserted(drv->blk)) { FLOPPY_DPRINTF("No disk in drive\n"); drv->disk = FLOPPY_DRIVE_TYPE_NONE; @@ -479,8 +479,8 @@ static void fd_change_cb(void *opaque, bool load, Error **errp) blk_set_perm(drive->blk, 0, BLK_PERM_ALL, &error_abort); } else { if (!blkconf_apply_backend_options(drive->conf, - blk_is_read_only(drive->blk), false, - errp)) { + !blk_supports_write_perm(drive->blk), + false, errp)) { return; } } @@ -553,7 +553,8 @@ static void floppy_drive_realize(DeviceState *qdev, Error **errp) * read-only node later */ read_only = true; } else { - read_only = !blk_bs(dev->conf.blk) || blk_is_read_only(dev->conf.blk); + read_only = !blk_bs(dev->conf.blk) || + !blk_supports_write_perm(dev->conf.blk); } if (!blkconf_blocksizes(&dev->conf, errp)) { diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index b744a58d1c..0412d3e7f4 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -508,7 +508,7 @@ static void flash_sync_page(Flash *s, int page) { QEMUIOVector *iov; - if (!s->blk || blk_is_read_only(s->blk)) { + if (!s->blk || !blk_is_writable(s->blk)) { return; } @@ -524,7 +524,7 @@ static inline void flash_sync_area(Flash *s, int64_t off, int64_t len) { QEMUIOVector *iov; - if (!s->blk || blk_is_read_only(s->blk)) { + if (!s->blk || !blk_is_writable(s->blk)) { return; } @@ -1434,7 +1434,7 @@ static void m25p80_realize(SSIPeripheral *ss, Error **errp) if (s->blk) { uint64_t perm = BLK_PERM_CONSISTENT_READ | - (blk_is_read_only(s->blk) ? 0 : BLK_PERM_WRITE); + (blk_supports_write_perm(s->blk) ? BLK_PERM_WRITE : 0); ret = blk_set_perm(s->blk, perm, BLK_PERM_ALL, errp); if (ret < 0) { return; diff --git a/hw/block/nand.c b/hw/block/nand.c index 913292ad1d..8bc80e3514 100644 --- a/hw/block/nand.c +++ b/hw/block/nand.c @@ -400,7 +400,7 @@ static void nand_realize(DeviceState *dev, Error **errp) pagesize = 1 << s->oob_shift; s->mem_oob = 1; if (s->blk) { - if (blk_is_read_only(s->blk)) { + if (!blk_supports_write_perm(s->blk)) { error_setg(errp, "Can't use a read-only drive"); return; } diff --git a/hw/block/nvme-ns.c b/hw/block/nvme-ns.c index 31c80cdf5b..2670787d26 100644 --- a/hw/block/nvme-ns.c +++ b/hw/block/nvme-ns.c @@ -48,13 +48,14 @@ static void nvme_ns_init(NvmeNamespace *ns) static int nvme_ns_init_blk(NvmeCtrl *n, NvmeNamespace *ns, Error **errp) { + bool read_only; + if (!blkconf_blocksizes(&ns->blkconf, errp)) { return -1; } - if (!blkconf_apply_backend_options(&ns->blkconf, - blk_is_read_only(ns->blkconf.blk), - false, errp)) { + read_only = !blk_supports_write_perm(ns->blkconf.blk); + if (!blkconf_apply_backend_options(&ns->blkconf, read_only, false, errp)) { return -1; } diff --git a/hw/block/onenand.c b/hw/block/onenand.c index 579a73d7f7..afc0cd3a0f 100644 --- a/hw/block/onenand.c +++ b/hw/block/onenand.c @@ -797,7 +797,7 @@ static void onenand_realize(DeviceState *dev, Error **errp) s->image = memset(g_malloc(size + (size >> 5)), 0xff, size + (size >> 5)); } else { - if (blk_is_read_only(s->blk)) { + if (!blk_supports_write_perm(s->blk)) { error_setg(errp, "Can't use a read-only drive"); return; } diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c index ccf326793d..22287a1522 100644 --- a/hw/block/pflash_cfi01.c +++ b/hw/block/pflash_cfi01.c @@ -745,7 +745,7 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp) if (pfl->blk) { uint64_t perm; - pfl->ro = blk_is_read_only(pfl->blk); + pfl->ro = !blk_supports_write_perm(pfl->blk); perm = BLK_PERM_CONSISTENT_READ | (pfl->ro ? 0 : BLK_PERM_WRITE); ret = blk_set_perm(pfl->blk, perm, BLK_PERM_ALL, errp); if (ret < 0) { diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c index 2ad2f6baea..7962cff745 100644 --- a/hw/block/pflash_cfi02.c +++ b/hw/block/pflash_cfi02.c @@ -802,7 +802,7 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp) if (pfl->blk) { uint64_t perm; - pfl->ro = blk_is_read_only(pfl->blk); + pfl->ro = !blk_supports_write_perm(pfl->blk); perm = BLK_PERM_CONSISTENT_READ | (pfl->ro ? 0 : BLK_PERM_WRITE); ret = blk_set_perm(pfl->blk, perm, BLK_PERM_ALL, errp); if (ret < 0) { diff --git a/hw/block/swim.c b/hw/block/swim.c index 20133a814c..509c2f4900 100644 --- a/hw/block/swim.c +++ b/hw/block/swim.c @@ -137,8 +137,8 @@ static void swim_change_cb(void *opaque, bool load, Error **errp) blk_set_perm(drive->blk, 0, BLK_PERM_ALL, &error_abort); } else { if (!blkconf_apply_backend_options(drive->conf, - blk_is_read_only(drive->blk), false, - errp)) { + !blk_supports_write_perm(drive->blk), + false, errp)) { return; } } @@ -210,7 +210,7 @@ static void swim_drive_realize(DeviceState *qdev, Error **errp) dev->conf.werror = BLOCKDEV_ON_ERROR_AUTO; if (!blkconf_apply_backend_options(&dev->conf, - blk_is_read_only(dev->conf.blk), + !blk_supports_write_perm(dev->conf.blk), false, errp)) { return; } diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index bac2d6fa2b..e8600b069d 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -1021,7 +1021,7 @@ static uint64_t virtio_blk_get_features(VirtIODevice *vdev, uint64_t features, virtio_has_feature(features, VIRTIO_BLK_F_CONFIG_WCE))) { virtio_add_feature(&features, VIRTIO_BLK_F_WCE); } - if (blk_is_read_only(s->blk)) { + if (!blk_is_writable(s->blk)) { virtio_add_feature(&features, VIRTIO_BLK_F_RO); } if (s->conf.num_queues > 1) { @@ -1175,8 +1175,8 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp) } if (!blkconf_apply_backend_options(&conf->conf, - blk_is_read_only(conf->conf.blk), true, - errp)) { + !blk_supports_write_perm(conf->conf.blk), + true, errp)) { return; } s->original_wce = blk_enable_write_cache(conf->conf.blk); diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c index 718d886e5c..0e7d66c2a7 100644 --- a/hw/block/xen-block.c +++ b/hw/block/xen-block.c @@ -567,7 +567,7 @@ static void xen_disk_realize(XenBlockDevice *blockdev, Error **errp) return; } - blockdev->info = blk_is_read_only(conf->blk) ? VDISK_READONLY : 0; + blockdev->info = blk_supports_write_perm(conf->blk) ? 0 : VDISK_READONLY; } static void xen_disk_class_init(ObjectClass *class, void *data) diff --git a/hw/ide/core.c b/hw/ide/core.c index b49e4cfbc6..81db2c95de 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -2537,7 +2537,7 @@ int ide_init_drive(IDEState *s, BlockBackend *blk, IDEDriveKind kind, error_setg(errp, "Device needs media, but drive is empty"); return -1; } - if (blk_is_read_only(blk)) { + if (!blk_is_writable(blk)) { error_setg(errp, "Can't use a read-only drive"); return -1; } diff --git a/hw/misc/sifive_u_otp.c b/hw/misc/sifive_u_otp.c index f921c67644..b8e8b9eebe 100644 --- a/hw/misc/sifive_u_otp.c +++ b/hw/misc/sifive_u_otp.c @@ -228,7 +228,7 @@ static void sifive_u_otp_realize(DeviceState *dev, Error **errp) if (s->blk) { perm = BLK_PERM_CONSISTENT_READ | - (blk_is_read_only(s->blk) ? 0 : BLK_PERM_WRITE); + (blk_supports_write_perm(s->blk) ? BLK_PERM_WRITE : 0); ret = blk_set_perm(s->blk, perm, BLK_PERM_ALL, errp); if (ret < 0) { return; diff --git a/hw/ppc/pnv_pnor.c b/hw/ppc/pnv_pnor.c index ef8dff03e0..4b455de1ea 100644 --- a/hw/ppc/pnv_pnor.c +++ b/hw/ppc/pnv_pnor.c @@ -86,7 +86,7 @@ static void pnv_pnor_realize(DeviceState *dev, Error **errp) if (s->blk) { uint64_t perm = BLK_PERM_CONSISTENT_READ | - (blk_is_read_only(s->blk) ? 0 : BLK_PERM_WRITE); + (blk_supports_write_perm(s->blk) ? BLK_PERM_WRITE : 0); ret = blk_set_perm(s->blk, perm, BLK_PERM_ALL, errp); if (ret < 0) { return; diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 29504ea081..ed52fcd49f 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -1270,7 +1270,7 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf) if (s->qdev.type == TYPE_DISK) { dev_specific_param = s->features & (1 << SCSI_DISK_F_DPOFUA) ? 0x10 : 0; - if (blk_is_read_only(s->qdev.conf.blk)) { + if (!blk_is_writable(s->qdev.conf.blk)) { dev_specific_param |= 0x80; /* Readonly. */ } } else { @@ -1704,7 +1704,7 @@ static void scsi_disk_emulate_unmap(SCSIDiskReq *r, uint8_t *inbuf) goto invalid_param_len; } - if (blk_is_read_only(s->qdev.conf.blk)) { + if (!blk_is_writable(s->qdev.conf.blk)) { block_acct_invalid(blk_get_stats(s->qdev.conf.blk), BLOCK_ACCT_UNMAP); scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED)); return; @@ -1795,7 +1795,7 @@ static void scsi_disk_emulate_write_same(SCSIDiskReq *r, uint8_t *inbuf) return; } - if (blk_is_read_only(s->qdev.conf.blk)) { + if (!blk_is_writable(s->qdev.conf.blk)) { scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED)); return; } @@ -2207,7 +2207,7 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf) case WRITE_VERIFY_10: case WRITE_VERIFY_12: case WRITE_VERIFY_16: - if (blk_is_read_only(s->qdev.conf.blk)) { + if (!blk_is_writable(s->qdev.conf.blk)) { scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED)); return 0; } @@ -2380,7 +2380,7 @@ static void scsi_realize(SCSIDevice *dev, Error **errp) } } - read_only = blk_is_read_only(s->qdev.conf.blk); + read_only = !blk_supports_write_perm(s->qdev.conf.blk); if (dev->type == TYPE_ROM) { read_only = true; } diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c index 9740f7e36a..ab220141f5 100644 --- a/hw/scsi/scsi-generic.c +++ b/hw/scsi/scsi-generic.c @@ -306,7 +306,7 @@ static void scsi_read_complete(void * opaque, int ret) * readonly. */ if ((s->type == TYPE_DISK || s->type == TYPE_TAPE || s->type == TYPE_ZBC) && - blk_is_read_only(s->conf.blk) && + !blk_is_writable(s->conf.blk) && (r->req.cmd.buf[0] == MODE_SENSE || r->req.cmd.buf[0] == MODE_SENSE_10) && (r->req.cmd.buf[1] & 0x8) == 0) { @@ -694,7 +694,7 @@ static void scsi_generic_realize(SCSIDevice *s, Error **errp) return; } if (!blkconf_apply_backend_options(&s->conf, - blk_is_read_only(s->conf.blk), + !blk_supports_write_perm(s->conf.blk), true, errp)) { return; } diff --git a/hw/sd/sd.c b/hw/sd/sd.c index b3952514fe..8517dbce8b 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -567,7 +567,7 @@ static void sd_reset(DeviceState *dev) sd_set_sdstatus(sd); g_free(sd->wp_groups); - sd->wp_switch = sd->blk ? blk_is_read_only(sd->blk) : false; + sd->wp_switch = sd->blk ? !blk_is_writable(sd->blk) : false; sd->wpgrps_size = sect; sd->wp_groups = bitmap_new(sd->wpgrps_size); memset(sd->function_group, 0, sizeof(sd->function_group)); @@ -735,7 +735,7 @@ void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert) { sd->readonly_cb = readonly; sd->inserted_cb = insert; - qemu_set_irq(readonly, sd->blk ? blk_is_read_only(sd->blk) : 0); + qemu_set_irq(readonly, sd->blk ? !blk_is_writable(sd->blk) : 0); qemu_set_irq(insert, sd->blk ? blk_is_inserted(sd->blk) : 0); } @@ -2131,7 +2131,7 @@ static void sd_realize(DeviceState *dev, Error **errp) if (sd->blk) { int64_t blk_size; - if (blk_is_read_only(sd->blk)) { + if (!blk_supports_write_perm(sd->blk)) { error_setg(errp, "Cannot use read-only drive as SD card"); return; } diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index f0f005869d..c49e8b819e 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -613,8 +613,8 @@ static void usb_msd_storage_realize(USBDevice *dev, Error **errp) return; } - if (!blkconf_apply_backend_options(&s->conf, blk_is_read_only(blk), true, - errp)) { + if (!blkconf_apply_backend_options(&s->conf, !blk_supports_write_perm(blk), + true, errp)) { return; } diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h index 8203d7f6f9..880e903293 100644 --- a/include/sysemu/block-backend.h +++ b/include/sysemu/block-backend.h @@ -191,7 +191,8 @@ BlockErrorAction blk_get_error_action(BlockBackend *blk, bool is_read, int error); void blk_error_action(BlockBackend *blk, BlockErrorAction action, bool is_read, int error); -bool blk_is_read_only(BlockBackend *blk); +bool blk_supports_write_perm(BlockBackend *blk); +bool blk_is_writable(BlockBackend *blk); bool blk_is_sg(BlockBackend *blk); bool blk_enable_write_cache(BlockBackend *blk); void blk_set_enable_write_cache(BlockBackend *blk, bool wce); diff --git a/tests/check-block.sh b/tests/check-block.sh index e4f37905be..f86cb863de 100755 --- a/tests/check-block.sh +++ b/tests/check-block.sh @@ -73,10 +73,11 @@ cd tests/qemu-iotests # QEMU_CHECK_BLOCK_AUTO is used to disable some unstable sub-tests export QEMU_CHECK_BLOCK_AUTO=1 +export PYTHONUTF8=1 ret=0 for fmt in $format_list ; do - ./check -makecheck -$fmt $group || ret=1 + ${PYTHON} ./check -makecheck -$fmt $group || ret=1 done exit $ret diff --git a/tests/qemu-iotests/146.out b/tests/qemu-iotests/146.out index 80513cdd06..c67ba4ba7c 100644 --- a/tests/qemu-iotests/146.out +++ b/tests/qemu-iotests/146.out @@ -2,414 +2,414 @@ QA output created by 146 === Testing VPC Autodetect === -[{ "start": 0, "length": 136363130880, "depth": 0, "zero": true, "data": false }] +[{ "start": 0, "length": 136363130880, "depth": 0, "zero": true, "data": false}] === Testing VPC with current_size force === -[{ "start": 0, "length": 136365211648, "depth": 0, "zero": true, "data": false }] +[{ "start": 0, "length": 136365211648, "depth": 0, "zero": true, "data": false}] === Testing VPC with chs force === -[{ "start": 0, "length": 136363130880, "depth": 0, "zero": true, "data": false }] +[{ "start": 0, "length": 136363130880, "depth": 0, "zero": true, "data": false}] === Testing Hyper-V Autodetect === -[{ "start": 0, "length": 136365211648, "depth": 0, "zero": true, "data": false }] +[{ "start": 0, "length": 136365211648, "depth": 0, "zero": true, "data": false}] === Testing Hyper-V with current_size force === -[{ "start": 0, "length": 136365211648, "depth": 0, "zero": true, "data": false }] +[{ "start": 0, "length": 136365211648, "depth": 0, "zero": true, "data": false}] === Testing Hyper-V with chs force === -[{ "start": 0, "length": 136363130880, "depth": 0, "zero": true, "data": false }] +[{ "start": 0, "length": 136363130880, "depth": 0, "zero": true, "data": false}] === Testing d2v Autodetect === -[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 4194304, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 6291456, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 8388608, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 10485760, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 12582912, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 14680064, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 16777216, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 18874368, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 20971520, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 23068672, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 25165824, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 27262976, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 29360128, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 31457280, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 33554432, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 35651584, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 37748736, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 39845888, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 41943040, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 44040192, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 46137344, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 48234496, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 50331648, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 52428800, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 54525952, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 56623104, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 58720256, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 60817408, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 62914560, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 65011712, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 67108864, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 69206016, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 71303168, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 73400320, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 75497472, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 77594624, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 79691776, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 81788928, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 83886080, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 85983232, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 88080384, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 90177536, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 92274688, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 94371840, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 96468992, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 98566144, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 100663296, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 102760448, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 104857600, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 106954752, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 109051904, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 111149056, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 113246208, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 115343360, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 117440512, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 119537664, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 121634816, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 123731968, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 125829120, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 127926272, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 130023424, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 132120576, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 134217728, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 136314880, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 138412032, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 140509184, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 142606336, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 144703488, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 146800640, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 148897792, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 150994944, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 153092096, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 155189248, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 157286400, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 159383552, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 161480704, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 163577856, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 165675008, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 167772160, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 169869312, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 171966464, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 174063616, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 176160768, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 178257920, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 180355072, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 182452224, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 184549376, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 186646528, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 188743680, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 190840832, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 192937984, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 195035136, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 197132288, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 199229440, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 201326592, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 203423744, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 205520896, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 207618048, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 209715200, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 211812352, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 213909504, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 216006656, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 218103808, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 220200960, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 222298112, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 224395264, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 226492416, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 228589568, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 230686720, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 232783872, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 234881024, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 236978176, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 239075328, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 241172480, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 243269632, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 245366784, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 247463936, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 249561088, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 251658240, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 253755392, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 255852544, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 257949696, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 260046848, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 262144000, "length": 1310720, "depth": 0, "zero": false, "data": true, "offset": OFFSET }] +[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 4194304, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 6291456, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 8388608, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 10485760, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 12582912, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 14680064, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 16777216, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 18874368, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 20971520, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 23068672, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 25165824, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 27262976, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 29360128, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 31457280, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 33554432, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 35651584, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 37748736, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 39845888, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 41943040, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 44040192, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 46137344, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 48234496, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 50331648, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 52428800, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 54525952, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 56623104, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 58720256, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 60817408, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 62914560, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 65011712, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 67108864, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 69206016, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 71303168, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 73400320, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 75497472, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 77594624, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 79691776, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 81788928, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 83886080, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 85983232, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 88080384, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 90177536, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 92274688, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 94371840, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 96468992, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 98566144, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 100663296, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 102760448, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 104857600, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 106954752, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 109051904, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 111149056, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 113246208, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 115343360, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 117440512, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 119537664, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 121634816, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 123731968, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 125829120, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 127926272, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 130023424, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 132120576, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 134217728, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 136314880, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 138412032, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 140509184, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 142606336, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 144703488, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 146800640, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 148897792, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 150994944, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 153092096, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 155189248, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 157286400, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 159383552, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 161480704, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 163577856, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 165675008, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 167772160, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 169869312, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 171966464, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 174063616, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 176160768, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 178257920, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 180355072, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 182452224, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 184549376, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 186646528, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 188743680, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 190840832, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 192937984, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 195035136, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 197132288, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 199229440, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 201326592, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 203423744, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 205520896, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 207618048, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 209715200, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 211812352, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 213909504, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 216006656, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 218103808, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 220200960, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 222298112, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 224395264, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 226492416, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 228589568, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 230686720, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 232783872, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 234881024, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 236978176, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 239075328, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 241172480, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 243269632, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 245366784, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 247463936, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 249561088, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 251658240, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 253755392, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 255852544, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 257949696, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 260046848, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 262144000, "length": 1310720, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] === Testing d2v with current_size force === -[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 4194304, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 6291456, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 8388608, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 10485760, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 12582912, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 14680064, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 16777216, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 18874368, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 20971520, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 23068672, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 25165824, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 27262976, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 29360128, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 31457280, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 33554432, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 35651584, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 37748736, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 39845888, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 41943040, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 44040192, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 46137344, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 48234496, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 50331648, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 52428800, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 54525952, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 56623104, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 58720256, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 60817408, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 62914560, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 65011712, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 67108864, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 69206016, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 71303168, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 73400320, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 75497472, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 77594624, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 79691776, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 81788928, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 83886080, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 85983232, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 88080384, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 90177536, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 92274688, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 94371840, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 96468992, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 98566144, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 100663296, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 102760448, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 104857600, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 106954752, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 109051904, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 111149056, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 113246208, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 115343360, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 117440512, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 119537664, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 121634816, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 123731968, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 125829120, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 127926272, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 130023424, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 132120576, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 134217728, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 136314880, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 138412032, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 140509184, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 142606336, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 144703488, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 146800640, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 148897792, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 150994944, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 153092096, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 155189248, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 157286400, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 159383552, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 161480704, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 163577856, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 165675008, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 167772160, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 169869312, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 171966464, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 174063616, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 176160768, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 178257920, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 180355072, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 182452224, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 184549376, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 186646528, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 188743680, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 190840832, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 192937984, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 195035136, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 197132288, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 199229440, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 201326592, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 203423744, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 205520896, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 207618048, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 209715200, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 211812352, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 213909504, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 216006656, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 218103808, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 220200960, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 222298112, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 224395264, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 226492416, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 228589568, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 230686720, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 232783872, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 234881024, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 236978176, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 239075328, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 241172480, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 243269632, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 245366784, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 247463936, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 249561088, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 251658240, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 253755392, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 255852544, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 257949696, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 260046848, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 262144000, "length": 1310720, "depth": 0, "zero": false, "data": true, "offset": OFFSET }] +[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 4194304, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 6291456, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 8388608, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 10485760, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 12582912, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 14680064, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 16777216, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 18874368, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 20971520, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 23068672, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 25165824, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 27262976, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 29360128, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 31457280, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 33554432, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 35651584, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 37748736, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 39845888, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 41943040, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 44040192, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 46137344, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 48234496, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 50331648, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 52428800, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 54525952, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 56623104, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 58720256, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 60817408, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 62914560, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 65011712, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 67108864, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 69206016, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 71303168, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 73400320, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 75497472, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 77594624, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 79691776, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 81788928, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 83886080, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 85983232, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 88080384, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 90177536, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 92274688, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 94371840, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 96468992, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 98566144, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 100663296, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 102760448, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 104857600, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 106954752, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 109051904, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 111149056, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 113246208, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 115343360, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 117440512, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 119537664, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 121634816, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 123731968, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 125829120, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 127926272, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 130023424, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 132120576, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 134217728, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 136314880, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 138412032, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 140509184, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 142606336, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 144703488, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 146800640, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 148897792, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 150994944, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 153092096, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 155189248, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 157286400, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 159383552, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 161480704, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 163577856, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 165675008, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 167772160, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 169869312, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 171966464, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 174063616, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 176160768, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 178257920, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 180355072, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 182452224, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 184549376, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 186646528, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 188743680, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 190840832, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 192937984, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 195035136, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 197132288, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 199229440, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 201326592, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 203423744, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 205520896, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 207618048, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 209715200, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 211812352, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 213909504, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 216006656, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 218103808, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 220200960, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 222298112, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 224395264, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 226492416, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 228589568, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 230686720, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 232783872, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 234881024, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 236978176, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 239075328, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 241172480, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 243269632, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 245366784, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 247463936, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 249561088, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 251658240, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 253755392, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 255852544, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 257949696, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 260046848, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 262144000, "length": 1310720, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] === Testing d2v with chs force === -[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 4194304, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 6291456, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 8388608, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 10485760, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 12582912, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 14680064, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 16777216, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 18874368, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 20971520, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 23068672, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 25165824, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 27262976, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 29360128, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 31457280, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 33554432, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 35651584, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 37748736, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 39845888, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 41943040, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 44040192, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 46137344, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 48234496, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 50331648, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 52428800, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 54525952, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 56623104, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 58720256, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 60817408, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 62914560, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 65011712, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 67108864, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 69206016, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 71303168, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 73400320, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 75497472, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 77594624, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 79691776, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 81788928, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 83886080, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 85983232, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 88080384, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 90177536, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 92274688, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 94371840, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 96468992, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 98566144, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 100663296, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 102760448, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 104857600, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 106954752, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 109051904, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 111149056, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 113246208, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 115343360, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 117440512, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 119537664, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 121634816, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 123731968, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 125829120, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 127926272, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 130023424, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 132120576, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 134217728, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 136314880, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 138412032, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 140509184, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 142606336, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 144703488, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 146800640, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 148897792, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 150994944, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 153092096, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 155189248, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 157286400, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 159383552, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 161480704, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 163577856, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 165675008, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 167772160, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 169869312, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 171966464, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 174063616, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 176160768, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 178257920, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 180355072, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 182452224, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 184549376, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 186646528, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 188743680, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 190840832, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 192937984, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 195035136, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 197132288, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 199229440, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 201326592, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 203423744, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 205520896, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 207618048, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 209715200, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 211812352, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 213909504, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 216006656, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 218103808, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 220200960, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 222298112, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 224395264, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 226492416, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 228589568, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 230686720, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 232783872, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 234881024, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 236978176, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 239075328, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 241172480, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 243269632, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 245366784, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 247463936, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 249561088, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 251658240, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 253755392, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 255852544, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 257949696, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 260046848, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET }, -{ "start": 262144000, "length": 1310720, "depth": 0, "zero": false, "data": true, "offset": OFFSET }] +[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 4194304, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 6291456, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 8388608, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 10485760, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 12582912, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 14680064, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 16777216, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 18874368, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 20971520, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 23068672, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 25165824, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 27262976, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 29360128, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 31457280, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 33554432, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 35651584, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 37748736, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 39845888, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 41943040, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 44040192, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 46137344, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 48234496, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 50331648, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 52428800, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 54525952, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 56623104, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 58720256, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 60817408, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 62914560, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 65011712, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 67108864, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 69206016, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 71303168, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 73400320, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 75497472, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 77594624, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 79691776, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 81788928, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 83886080, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 85983232, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 88080384, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 90177536, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 92274688, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 94371840, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 96468992, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 98566144, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 100663296, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 102760448, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 104857600, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 106954752, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 109051904, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 111149056, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 113246208, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 115343360, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 117440512, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 119537664, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 121634816, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 123731968, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 125829120, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 127926272, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 130023424, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 132120576, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 134217728, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 136314880, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 138412032, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 140509184, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 142606336, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 144703488, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 146800640, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 148897792, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 150994944, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 153092096, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 155189248, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 157286400, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 159383552, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 161480704, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 163577856, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 165675008, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 167772160, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 169869312, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 171966464, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 174063616, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 176160768, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 178257920, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 180355072, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 182452224, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 184549376, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 186646528, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 188743680, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 190840832, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 192937984, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 195035136, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 197132288, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 199229440, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 201326592, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 203423744, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 205520896, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 207618048, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 209715200, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 211812352, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 213909504, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 216006656, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 218103808, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 220200960, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 222298112, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 224395264, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 226492416, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 228589568, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 230686720, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 232783872, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 234881024, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 236978176, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 239075328, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 241172480, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 243269632, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 245366784, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 247463936, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 249561088, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 251658240, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 253755392, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 255852544, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 257949696, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 260046848, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, +{ "start": 262144000, "length": 1310720, "depth": 0, "zero": false, "data": true, "offset": OFFSET}] === Testing Image create, default === @@ -417,15 +417,15 @@ Formatting 'TEST_DIR/IMGFMT-create-test.IMGFMT', fmt=IMGFMT size=4294967296 === Read created image, default opts ==== -[{ "start": 0, "length": 4295467008, "depth": 0, "zero": true, "data": false }] +[{ "start": 0, "length": 4295467008, "depth": 0, "zero": true, "data": false}] === Read created image, force_size_calc=chs ==== -[{ "start": 0, "length": 4295467008, "depth": 0, "zero": true, "data": false }] +[{ "start": 0, "length": 4295467008, "depth": 0, "zero": true, "data": false}] === Read created image, force_size_calc=current_size ==== -[{ "start": 0, "length": 4295467008, "depth": 0, "zero": true, "data": false }] +[{ "start": 0, "length": 4295467008, "depth": 0, "zero": true, "data": false}] === Testing Image create, force_size === @@ -433,13 +433,13 @@ Formatting 'TEST_DIR/IMGFMT-create-test.IMGFMT', fmt=IMGFMT size=4294967296 === Read created image, default opts ==== -[{ "start": 0, "length": 4294967296, "depth": 0, "zero": true, "data": false }] +[{ "start": 0, "length": 4294967296, "depth": 0, "zero": true, "data": false}] === Read created image, force_size_calc=chs ==== -[{ "start": 0, "length": 4294967296, "depth": 0, "zero": true, "data": false }] +[{ "start": 0, "length": 4294967296, "depth": 0, "zero": true, "data": false}] === Read created image, force_size_calc=current_size ==== -[{ "start": 0, "length": 4294967296, "depth": 0, "zero": true, "data": false }] +[{ "start": 0, "length": 4294967296, "depth": 0, "zero": true, "data": false}] *** done diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check index 952762d5ed..5190dee82e 100755 --- a/tests/qemu-iotests/check +++ b/tests/qemu-iotests/check @@ -1,7 +1,8 @@ -#!/usr/bin/env bash +#!/usr/bin/env python3 # -# Copyright (C) 2009 Red Hat, Inc. -# Copyright (c) 2000-2002,2006 Silicon Graphics, Inc. All Rights Reserved. +# Configure environment and run group of tests in it. +# +# Copyright (c) 2020-2021 Virtuozzo International GmbH # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as @@ -14,967 +15,129 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -# -# -# Control script for QA -# - -status=0 -needwrap=true -try=0 -n_bad=0 -bad="" -notrun="" -casenotrun="" -interrupt=true -makecheck=false - -_init_error() -{ - echo "check: $1" >&2 - exit 1 -} - -if [ -L "$0" ] -then - # called from the build tree - source_iotests=$(dirname "$(readlink "$0")") - if [ -z "$source_iotests" ] - then - _init_error "failed to obtain source tree name from check symlink" - fi - source_iotests=$(cd "$source_iotests"; pwd) || _init_error "failed to enter source tree" - build_iotests=$(cd "$(dirname "$0")"; pwd) -else - # called from the source tree - source_iotests=$PWD - # this may be an in-tree build (note that in the following code we may not - # assume that it truly is and have to test whether the build results - # actually exist) - build_iotests=$PWD -fi - -build_root="$build_iotests/../.." - -# we need common.env -if ! . "$build_iotests/common.env" -then - _init_error "failed to source common.env (make sure the qemu-iotests are run from tests/qemu-iotests in the build tree)" -fi - -# we need common.config -if ! . "$source_iotests/common.config" -then - _init_error "failed to source common.config" -fi - -_full_imgfmt_details() -{ - if [ -n "$IMGOPTS" ]; then - echo "$IMGFMT ($IMGOPTS)" - else - echo "$IMGFMT" - fi -} - -_full_platform_details() -{ - os=$(uname -s) - host=$(hostname -s) - kernel=$(uname -r) - platform=$(uname -m) - echo "$os/$platform $host $kernel" -} - -_full_env_details() -{ - cat <<EOF -QEMU -- "$QEMU_PROG" $QEMU_OPTIONS -QEMU_IMG -- "$QEMU_IMG_PROG" $QEMU_IMG_OPTIONS -QEMU_IO -- "$QEMU_IO_PROG" $QEMU_IO_OPTIONS -QEMU_NBD -- "$QEMU_NBD_PROG" $QEMU_NBD_OPTIONS -IMGFMT -- $FULL_IMGFMT_DETAILS -IMGPROTO -- $IMGPROTO -PLATFORM -- $FULL_HOST_DETAILS -TEST_DIR -- $TEST_DIR -SOCK_DIR -- $SOCK_DIR -SOCKET_SCM_HELPER -- $SOCKET_SCM_HELPER - -EOF -} - -# $1 = prog to look for -set_prog_path() -{ - p=$(command -v $1 2> /dev/null) - if [ -n "$p" -a -x "$p" ]; then - type -p "$p" - else - return 1 - fi -} - -if [ -z "$TEST_DIR" ]; then - TEST_DIR=$PWD/scratch -fi -mkdir -p "$TEST_DIR" || _init_error 'Failed to create TEST_DIR' - -tmp_sock_dir=false -if [ -z "$SOCK_DIR" ]; then - SOCK_DIR=$(mktemp -d) - tmp_sock_dir=true -fi -mkdir -p "$SOCK_DIR" || _init_error 'Failed to create SOCK_DIR' - -diff="diff -u" -verbose=false -debug=false -group=false -xgroup=false -imgopts=false -showme=false -sortme=false -expunge=true -have_test_arg=false -cachemode=false -aiomode=false - -tmp="${TEST_DIR}"/$$ -rm -f $tmp.list $tmp.tmp $tmp.sed - -export IMGFMT=raw -export IMGFMT_GENERIC=true -export IMGPROTO=file -export IMGOPTS="" -export CACHEMODE="writeback" -export AIOMODE="threads" -export QEMU_IO_OPTIONS="" -export QEMU_IO_OPTIONS_NO_FMT="" -export CACHEMODE_IS_DEFAULT=true -export VALGRIND_QEMU= -export IMGKEYSECRET= -export IMGOPTSSYNTAX=false - -# Save current tty settings, since an aborting qemu call may leave things -# screwed up -STTY_RESTORE= -if test -t 0; then - STTY_RESTORE=$(stty -g) -fi - -for r -do - - if $group - then - # arg after -g - group_list=$(sed -n <"$source_iotests/group" -e 's/$/ /' -e "/^[0-9][0-9][0-9].* $r /"'{ -s/ .*//p -}') - if [ -z "$group_list" ] - then - echo "Group \"$r\" is empty or not defined?" - exit 1 - fi - [ ! -s $tmp.list ] && touch $tmp.list - for t in $group_list - do - if grep -s "^$t\$" $tmp.list >/dev/null - then - : - else - echo "$t" >>$tmp.list - fi - done - group=false - continue - - elif $xgroup - then - # arg after -x - # Populate $tmp.list with all tests - awk '/^[0-9]{3,}/ {print $1}' "${source_iotests}/group" > $tmp.list 2>/dev/null - group_list=$(sed -n <"$source_iotests/group" -e 's/$/ /' -e "/^[0-9][0-9][0-9].* $r /"'{ -s/ .*//p -}') - if [ -z "$group_list" ] - then - echo "Group \"$r\" is empty or not defined?" - exit 1 - fi - numsed=0 - rm -f $tmp.sed - for t in $group_list - do - if [ $numsed -gt 100 ] - then - sed -f $tmp.sed <$tmp.list >$tmp.tmp - mv $tmp.tmp $tmp.list - numsed=0 - rm -f $tmp.sed - fi - echo "/^$t\$/d" >>$tmp.sed - numsed=$(expr $numsed + 1) - done - sed -f $tmp.sed <$tmp.list >$tmp.tmp - mv $tmp.tmp $tmp.list - xgroup=false - continue - - elif $imgopts - then - IMGOPTS="$r" - imgopts=false - continue - elif $cachemode - then - CACHEMODE="$r" - CACHEMODE_IS_DEFAULT=false - cachemode=false - continue - elif $aiomode - then - AIOMODE="$r" - aiomode=false - continue - fi - - xpand=true - case "$r" - in - - -\? | -h | --help) # usage - echo "Usage: $0 [options] [testlist]"' - -common options - -v verbose - -d debug - -image format options - -raw test raw (default) - -bochs test bochs - -cloop test cloop - -parallels test parallels - -qcow test qcow - -qcow2 test qcow2 - -qed test qed - -vdi test vdi - -vpc test vpc - -vhdx test vhdx - -vmdk test vmdk - -luks test luks - -dmg test dmg - -image protocol options - -file test file (default) - -rbd test rbd - -sheepdog test sheepdog - -nbd test nbd - -fuse test fuse - -ssh test ssh - -nfs test nfs - -other options - -xdiff graphical mode diff - -nocache use O_DIRECT on backing file - -misalign misalign memory allocations - -n show me, do not run tests - -o options -o options to pass to qemu-img create/convert - -c mode cache mode - -i mode AIO mode - -makecheck pretty print output for make check - -testlist options - -g group[,group...] include tests from these groups - -x group[,group...] exclude tests from these groups - NNN include test NNN - NNN-NNN include test range (eg. 012-021) -' - exit 0 - ;; - - -raw) - IMGFMT=raw - xpand=false - ;; - - -bochs) - IMGFMT=bochs - IMGFMT_GENERIC=false - xpand=false - ;; - - -cloop) - IMGFMT=cloop - IMGFMT_GENERIC=false - xpand=false - ;; - - -parallels) - IMGFMT=parallels - xpand=false - ;; - - -qcow) - IMGFMT=qcow - xpand=false - ;; - - -qcow2) - IMGFMT=qcow2 - xpand=false - ;; - - -luks) - IMGOPTSSYNTAX=true - IMGFMT=luks - IMGKEYSECRET=123456 - xpand=false - ;; - - -dmg) - IMGFMT=dmg - IMGFMT_GENERIC=false - xpand=false - ;; - - -qed) - IMGFMT=qed - xpand=false - ;; - - -vdi) - IMGFMT=vdi - xpand=false - ;; - - -vmdk) - IMGFMT=vmdk - xpand=false - ;; - - -vpc) - IMGFMT=vpc - xpand=false - ;; - - -vhdx) - IMGFMT=vhdx - xpand=false - ;; - - -file) - IMGPROTO=file - xpand=false - ;; - - -rbd) - IMGPROTO=rbd - xpand=false - ;; - - -sheepdog) - IMGPROTO=sheepdog - xpand=false - ;; - - -nbd) - IMGPROTO=nbd - xpand=false - ;; - - -fuse) - IMGPROTO=fuse - xpand=false - ;; - - -ssh) - IMGPROTO=ssh - xpand=false - ;; - - -nfs) - IMGPROTO=nfs - xpand=false - ;; - - -nocache) - CACHEMODE="none" - CACHEMODE_IS_DEFAULT=false - xpand=false - ;; - - -misalign) - QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS --misalign" - xpand=false - ;; - - -valgrind) - VALGRIND_QEMU='y' - xpand=false - ;; - - -g) # -g group ... pick from group file - group=true - xpand=false - ;; - - -xdiff) # graphical diff mode - xpand=false - - if [ ! -z "$DISPLAY" ] - then - command -v xdiff >/dev/null 2>&1 && diff=xdiff - command -v gdiff >/dev/null 2>&1 && diff=gdiff - command -v tkdiff >/dev/null 2>&1 && diff=tkdiff - command -v xxdiff >/dev/null 2>&1 && diff=xxdiff - fi - ;; - -makecheck) # makecheck friendly output - makecheck=true - xpand=false - ;; - -n) # show me, don't do it - showme=true - xpand=false - ;; - -o) - imgopts=true - xpand=false - ;; - -c) - cachemode=true - xpand=false - ;; - -i) - aiomode=true - xpand=false - ;; - -T) # deprecated timestamp option - xpand=false - ;; - -v) - verbose=true - xpand=false - ;; - -d) - debug=true - xpand=false - ;; - -x) # -x group ... exclude from group file - xgroup=true - xpand=false - ;; - '[0-9][0-9][0-9] [0-9][0-9][0-9][0-9]') - echo "No tests?" - status=1 - exit $status - ;; - - [0-9]*-[0-9]*) - eval $(echo $r | sed -e 's/^/start=/' -e 's/-/ end=/') - ;; - - [0-9]*-) - eval $(echo $r | sed -e 's/^/start=/' -e 's/-//') - end=$(echo [0-9][0-9][0-9] [0-9][0-9][0-9][0-9] | sed -e 's/\[0-9]//g' -e 's/ *$//' -e 's/.* //') - if [ -z "$end" ] - then - echo "No tests in range \"$r\"?" - status=1 - exit $status - fi - ;; - - *) - start=$r - end=$r - ;; - - esac - - # get rid of leading 0s as can be interpreted as octal - start=$(echo $start | sed 's/^0*//') - end=$(echo $end | sed 's/^0*//') - - if $xpand - then - have_test_arg=true - awk </dev/null ' -BEGIN { for (t='$start'; t<='$end'; t++) printf "%03d\n",t }' \ - | while read id - do - if grep -s "^$id\( \|\$\)" "$source_iotests/group" >/dev/null - then - # in group file ... OK - echo $id >>$tmp.list - else - if [ -f expunged ] && $expunge && egrep "^$id([ ]|\$)" expunged >/dev/null - then - # expunged ... will be reported, but not run, later - echo $id >>$tmp.list - else - # oops - if [ "$start" == "$end" -a "$id" == "$end" ] - then - echo "$id - unknown test" - exit 1 - else - echo "$id - unknown test, ignored" - fi - fi - fi - done || exit 1 - fi - -done - -# Set qemu-io cache mode with $CACHEMODE we have -QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS --cache $CACHEMODE" -# Set qemu-io aio mode with $AIOMODE we have -QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS --aio $AIOMODE" - -QEMU_IO_OPTIONS_NO_FMT="$QEMU_IO_OPTIONS" -if [ "$IMGOPTSSYNTAX" != "true" ]; then - QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS -f $IMGFMT" -fi - -# Set default options for qemu-img create -o if they were not specified -if [ "$IMGFMT" == "qcow2" ] && ! (echo "$IMGOPTS" | grep "compat=" > /dev/null); then - IMGOPTS=$(_optstr_add "$IMGOPTS" "compat=1.1") -fi -if [ "$IMGFMT" == "luks" ] && ! (echo "$IMGOPTS" | grep "iter-time=" > /dev/null); then - IMGOPTS=$(_optstr_add "$IMGOPTS" "iter-time=10") -fi -if [ "$IMGFMT" == "vmdk" ] && ! (echo "$IMGOPTS" | grep "zeroed_grain=" > /dev/null); then - IMGOPTS=$(_optstr_add "$IMGOPTS" "zeroed_grain=on") -fi - -if [ -z "$SAMPLE_IMG_DIR" ]; then - SAMPLE_IMG_DIR="$source_iotests/sample_images" -fi - -export TEST_DIR -export SOCK_DIR -export SAMPLE_IMG_DIR - -if [ -s $tmp.list ] -then - # found some valid test numbers ... this is good - : -else - if $have_test_arg - then - # had test numbers, but none in group file ... do nothing - touch $tmp.list - else - # no test numbers, do everything from group file - sed -n -e '/^[0-9][0-9][0-9]*/s/^\([0-9]*\).*/\1/p' <"$source_iotests/group" >$tmp.list - fi -fi - -# should be sort -n, but this did not work for Linux when this -# was ported from IRIX -# -list=$(sort $tmp.list) -rm -f $tmp.list $tmp.tmp $tmp.sed - -if [ -z "$QEMU_PROG" ] -then - if [ -x "$build_iotests/qemu" ]; then - export QEMU_PROG="$build_iotests/qemu" - elif [ -x "$build_root/qemu-system-${qemu_arch}" ]; then - export QEMU_PROG="$build_root/qemu-system-${qemu_arch}" - else - pushd "$build_root" > /dev/null - for binary in qemu-system-* - do - if [ -x "$binary" ] - then - export QEMU_PROG="$build_root/$binary" - break - fi - done - popd > /dev/null - [ "$QEMU_PROG" = "" ] && _init_error "qemu not found" - fi -fi -export QEMU_PROG="$(type -p "$QEMU_PROG")" - -export QEMU_OPTIONS="-nodefaults -display none -accel qtest" -case "$QEMU_PROG" in - *qemu-system-arm|*qemu-system-aarch64) - export QEMU_OPTIONS="$QEMU_OPTIONS -machine virt" - ;; - *qemu-system-avr) - export QEMU_OPTIONS="$QEMU_OPTIONS -machine mega2560" - ;; - *qemu-system-rx) - export QEMU_OPTIONS="$QEMU_OPTIONS -machine gdbsim-r5f562n8" - ;; - *qemu-system-tricore) - export QEMU_OPTIONS="-$QEMU_OPTIONS -machine tricore_testboard" - ;; -esac - -if [ -z "$QEMU_IMG_PROG" ]; then - if [ -x "$build_iotests/qemu-img" ]; then - export QEMU_IMG_PROG="$build_iotests/qemu-img" - elif [ -x "$build_root/qemu-img" ]; then - export QEMU_IMG_PROG="$build_root/qemu-img" - else - _init_error "qemu-img not found" - fi -fi -export QEMU_IMG_PROG="$(type -p "$QEMU_IMG_PROG")" - -if [ -z "$QEMU_IO_PROG" ]; then - if [ -x "$build_iotests/qemu-io" ]; then - export QEMU_IO_PROG="$build_iotests/qemu-io" - elif [ -x "$build_root/qemu-io" ]; then - export QEMU_IO_PROG="$build_root/qemu-io" - else - _init_error "qemu-io not found" - fi -fi -export QEMU_IO_PROG="$(type -p "$QEMU_IO_PROG")" - -if [ -z $QEMU_NBD_PROG ]; then - if [ -x "$build_iotests/qemu-nbd" ]; then - export QEMU_NBD_PROG="$build_iotests/qemu-nbd" - elif [ -x "$build_root/qemu-nbd" ]; then - export QEMU_NBD_PROG="$build_root/qemu-nbd" - else - _init_error "qemu-nbd not found" - fi -fi -export QEMU_NBD_PROG="$(type -p "$QEMU_NBD_PROG")" - -if [ -z "$QSD_PROG" ]; then - if [ -x "$build_iotests/qemu-storage-daemon" ]; then - export QSD_PROG="$build_iotests/qemu-storage-daemon" - elif [ -x "$build_root/storage-daemon/qemu-storage-daemon" ]; then - export QSD_PROG="$build_root/storage-daemon/qemu-storage-daemon" - else - _init_error "qemu-storage-daemon not found" - fi -fi -export QSD_PROG="$(type -p "$QSD_PROG")" - -if [ -x "$build_iotests/socket_scm_helper" ] -then - export SOCKET_SCM_HELPER="$build_iotests/socket_scm_helper" -fi - -python_usable=false -if $PYTHON -c 'import sys; sys.exit(0 if sys.version_info >= (3,6) else 1)' -then - # Our python framework also requires virtio-blk - if "$QEMU_PROG" -M none -device help | grep -q virtio-blk >/dev/null 2>&1 - then - python_usable=true - else - python_unusable_because="Missing virtio-blk in QEMU binary" - fi -else - python_unusable_because="Unsupported Python version" -fi - -default_machine=$($QEMU_PROG -machine help | sed -n '/(default)/ s/ .*//p') -default_alias_machine=$($QEMU_PROG -machine help | \ - sed -n "/(alias of $default_machine)/ { s/ .*//p; q; }") -if [[ "$default_alias_machine" ]]; then - default_machine="$default_alias_machine" -fi - -export QEMU_DEFAULT_MACHINE="$default_machine" - -TIMESTAMP_FILE=check.time-$IMGPROTO-$IMGFMT - -_wallclock() -{ - date "+%H %M %S" | awk '{ print $1*3600 + $2*60 + $3 }' -} - -_wrapup() -{ - if $showme - then - : - elif $needwrap - then - if [ -f $TIMESTAMP_FILE -a -f $tmp.time ] - then - cat $TIMESTAMP_FILE $tmp.time \ - | awk ' - { t[$1] = $2 } -END { if (NR > 0) { - for (i in t) print i " " t[i] - } - }' \ - | sort -n >$tmp.out - mv $tmp.out $TIMESTAMP_FILE - fi - - if [ -f $tmp.expunged ] - then - notrun=$(wc -l <$tmp.expunged | sed -e 's/ *//g') - try=$(expr $try - $notrun) - list=$(echo "$list" | sed -f $tmp.expunged) - fi - - echo "" >>check.log - date >>check.log - echo $list | fmt | sed -e 's/^/ /' >>check.log - $interrupt && echo "Interrupted!" >>check.log - - if [ ! -z "$notrun" ] - then - echo "Not run:$notrun" - echo "Not run:$notrun" >>check.log - fi - if [ ! -z "$casenotrun" ] - then - echo "Some cases not run in:$casenotrun" - echo "Some cases not run in:$casenotrun" >>check.log - fi - if [ ! -z "$n_bad" -a $n_bad != 0 ] - then - echo "Failures:$bad" - echo "Failed $n_bad of $try iotests" - echo "Failures:$bad" | fmt >>check.log - echo "Failed $n_bad of $try iotests" >>check.log - else - echo "Passed all $try iotests" - echo "Passed all $try iotests" >>check.log - fi - needwrap=false - fi - - if test -n "$STTY_RESTORE"; then - stty $STTY_RESTORE - fi - rm -f "${TEST_DIR}"/*.out "${TEST_DIR}"/*.err "${TEST_DIR}"/*.time - rm -f "${TEST_DIR}"/check.pid "${TEST_DIR}"/check.sts - rm -f $tmp.* - - if $tmp_sock_dir - then - rm -rf "$SOCK_DIR" - fi -} - -trap "_wrapup; exit \$status" 0 1 2 3 15 - -# Report the test start and results. For makecheck we want to pretty -# print the whole report at the end of the execution. -# args: $seq, $starttime, $lasttime -_report_test_start() -{ - if ! $makecheck; then - if [ -n "$3" ]; then - local lasttime=" (last: $3s)" - fi - printf "%-8s %-10s [%s] %4s%-14s\r" "$1" "..." "$2" "..." "$lasttime" - fi -} -# args:$seq $status $starttime $lasttime $thistime $details -_report_test_result() -{ - local status lasttime thistime - if $makecheck; then - if [ -n "$2" ] && [ "$2" != "pass" ]; then - status=" [$2]" - fi - printf " TEST iotest-$IMGFMT: %s%s\n" "$1" "$status" - return - fi - - if [ -n "$4" ]; then - lasttime=" (last: $4s)" - fi - if [ -n "$5" ]; then - thistime=" $5s" - fi - case "$2" in - "pass") status=$(printf "\e[32m%-10s\e[0m" "$2") ;; - "fail") status=$(printf "\e[1m\e[31m%-10s\e[0m" "$2") ;; - "not run") status=$(printf "\e[33m%-10s\e[0m" "$2") ;; - *) status=$(printf "%-10s" "$2") ;; - esac - - printf "%-8s %s [%s] [%s] %4s%-14s %s\n" "$1" "$status" "$3" "$(date '+%T')" "$thistime" "$lasttime" "$6" -} - -[ -f $TIMESTAMP_FILE ] || touch $TIMESTAMP_FILE - -FULL_IMGFMT_DETAILS=$(_full_imgfmt_details) -FULL_HOST_DETAILS=$(_full_platform_details) - -if ! $makecheck; then - _full_env_details -fi - -seq="check" - -[ -n "$TESTS_REMAINING_LOG" ] && echo $list > $TESTS_REMAINING_LOG - -for seq in $list -do - err=false # error flag - printdiff=false # show diff to reference output? - status="" # test result summary - results="" # test result details - thistime="" # time the test took - - if [ -n "$TESTS_REMAINING_LOG" ] ; then - sed -e "s/$seq//" -e 's/ / /' -e 's/^ *//' $TESTS_REMAINING_LOG > $TESTS_REMAINING_LOG.tmp - mv $TESTS_REMAINING_LOG.tmp $TESTS_REMAINING_LOG - sync - fi - - lasttime=$(sed -n -e "/^$seq /s/.* //p" <$TIMESTAMP_FILE) - starttime=$(date "+%T") - _report_test_start $seq $starttime $lasttime - - if $showme - then - status="not run" - elif [ -f expunged ] && $expunge && egrep "^$seq([ ]|\$)" expunged >/dev/null - then - status="not run" - results="expunged" - rm -f $seq.out.bad - echo "/^$seq\$/d" >>$tmp.expunged - elif [ ! -f "$source_iotests/$seq" ] - then - status="not run" - results="no such test?" - echo "/^$seq\$/d" >>$tmp.expunged - else - # really going to try and run this one - # - rm -f $seq.out.bad - rm -f core $seq.notrun - rm -f $seq.casenotrun - - start=$(_wallclock) - - if [ "$(head -n 1 "$source_iotests/$seq")" == "#!/usr/bin/env python3" ]; then - if $python_usable; then - run_command="$PYTHON $seq" - else - run_command="false" - echo "$python_unusable_because" > $seq.notrun - fi - else - run_command="./$seq" - fi - export OUTPUT_DIR=$PWD - if $debug; then - (cd "$source_iotests"; - MALLOC_PERTURB_=${MALLOC_PERTURB_:-$(($RANDOM % 255 + 1))} \ - $run_command -d 2>&1 | tee $tmp.out) - else - (cd "$source_iotests"; - MALLOC_PERTURB_=${MALLOC_PERTURB_:-$(($RANDOM % 255 + 1))} \ - $run_command >$tmp.out 2>&1) - fi - sts=$? - stop=$(_wallclock) - - if [ -f core ] - then - mv core $seq.core - status="fail" - results="[dumped core] $seq.core" - err=true - fi - - if [ -f $seq.notrun ] - then - # overwrites timestamp output - status="not run" - results="$(cat $seq.notrun)" - else - if [ $sts -ne 0 ] - then - status="fail" - results=$(printf %s "[failed, exit status $sts]") - err=true - fi - - reference="$source_iotests/$seq.out" - reference_machine="$source_iotests/$seq.$QEMU_DEFAULT_MACHINE.out" - if [ -f "$reference_machine" ]; then - reference="$reference_machine" - fi - - reference_format="$source_iotests/$seq.out.$IMGFMT" - if [ -f "$reference_format" ]; then - reference="$reference_format" - fi - - if [ "$CACHEMODE" = "none" ]; then - [ -f "$source_iotests/$seq.out.nocache" ] && reference="$source_iotests/$seq.out.nocache" - fi - - if [ ! -f "$reference" ] - then - status="fail" - results="no qualified output" - err=true - else - if diff -w "$reference" $tmp.out >/dev/null 2>&1 - then - if ! $err; then - status="pass" - thistime=$(expr $stop - $start) - echo "$seq $thistime" >>$tmp.time - fi - else - mv $tmp.out $seq.out.bad - status="fail" - results="output mismatch (see $seq.out.bad)" - printdiff=true - err=true - fi - fi - fi - if [ -f $seq.casenotrun ] - then - cat $seq.casenotrun - casenotrun="$casenotrun $seq" - fi - fi - - # come here for each test, except when $showme is true - # - _report_test_result $seq "$status" "$starttime" "$lasttime" "$thistime" "$results" - case "$status" in - "pass") - try=$(expr $try + 1) - ;; - "fail") - try=$(expr $try + 1) - if $makecheck; then - _full_env_details - fi - if $printdiff; then - $diff -w "$reference" "$PWD"/$seq.out.bad - fi - bad="$bad $seq" - n_bad=$(expr $n_bad + 1) - quick=false - ;; - "not run") - notrun="$notrun $seq" - ;; - esac - - seq="after_$seq" -done -interrupt=false -status=$(expr $n_bad) -exit +import os +import sys +import argparse +from findtests import TestFinder +from testenv import TestEnv +from testrunner import TestRunner + + +def make_argparser() -> argparse.ArgumentParser: + p = argparse.ArgumentParser(description="Test run options") + + p.add_argument('-n', '--dry-run', action='store_true', + help='show me, do not run tests') + p.add_argument('-makecheck', action='store_true', + help='pretty print output for make check') + + p.add_argument('-d', dest='debug', action='store_true', help='debug') + p.add_argument('-misalign', action='store_true', + help='misalign memory allocations') + p.add_argument('--color', choices=['on', 'off', 'auto'], + default='auto', help="use terminal colors. The default " + "'auto' value means use colors if terminal stdout detected") + + g_env = p.add_argument_group('test environment options') + mg = g_env.add_mutually_exclusive_group() + # We don't set default for cachemode, as we need to distinguish default + # from user input later. + mg.add_argument('-nocache', dest='cachemode', action='store_const', + const='none', help='set cache mode "none" (O_DIRECT), ' + 'sets CACHEMODE environment variable') + mg.add_argument('-c', dest='cachemode', + help='sets CACHEMODE environment variable') + + g_env.add_argument('-i', dest='aiomode', default='threads', + help='sets AIOMODE environment variable') + + p.set_defaults(imgfmt='raw', imgproto='file') + + format_list = ['raw', 'bochs', 'cloop', 'parallels', 'qcow', 'qcow2', + 'qed', 'vdi', 'vpc', 'vhdx', 'vmdk', 'luks', 'dmg'] + g_fmt = p.add_argument_group( + ' image format options', + 'The following options set the IMGFMT environment variable. ' + 'At most one choice is allowed, default is "raw"') + mg = g_fmt.add_mutually_exclusive_group() + for fmt in format_list: + mg.add_argument('-' + fmt, dest='imgfmt', action='store_const', + const=fmt, help=f'test {fmt}') + + protocol_list = ['file', 'rbd', 'sheepdog', 'nbd', 'ssh', 'nfs', + 'fuse'] + g_prt = p.add_argument_group( + ' image protocol options', + 'The following options set the IMGPROTO environment variable. ' + 'At most one choice is allowed, default is "file"') + mg = g_prt.add_mutually_exclusive_group() + for prt in protocol_list: + mg.add_argument('-' + prt, dest='imgproto', action='store_const', + const=prt, help=f'test {prt}') + + g_bash = p.add_argument_group('bash tests options', + 'The following options are ignored by ' + 'python tests.') + # TODO: make support for the following options in iotests.py + g_bash.add_argument('-o', dest='imgopts', + help='options to pass to qemu-img create/convert, ' + 'sets IMGOPTS environment variable') + g_bash.add_argument('-valgrind', action='store_true', + help='use valgrind, sets VALGRIND_QEMU environment ' + 'variable') + + g_sel = p.add_argument_group('test selecting options', + 'The following options specify test set ' + 'to run.') + g_sel.add_argument('-g', '--groups', metavar='group1,...', + help='include tests from these groups') + g_sel.add_argument('-x', '--exclude-groups', metavar='group1,...', + help='exclude tests from these groups') + g_sel.add_argument('--start-from', metavar='TEST', + help='Start from specified test: make sorted sequence ' + 'of tests as usual and then drop tests from the first ' + 'one to TEST (not inclusive). This may be used to ' + 'rerun failed ./check command, starting from the ' + 'middle of the process.') + g_sel.add_argument('tests', metavar='TEST_FILES', nargs='*', + help='tests to run') + + return p + + +if __name__ == '__main__': + args = make_argparser().parse_args() + + env = TestEnv(imgfmt=args.imgfmt, imgproto=args.imgproto, + aiomode=args.aiomode, cachemode=args.cachemode, + imgopts=args.imgopts, misalign=args.misalign, + debug=args.debug, valgrind=args.valgrind) + + testfinder = TestFinder(test_dir=env.source_iotests) + + groups = args.groups.split(',') if args.groups else None + x_groups = args.exclude_groups.split(',') if args.exclude_groups else None + + group_local = os.path.join(env.source_iotests, 'group.local') + if os.path.isfile(group_local): + try: + testfinder.add_group_file(group_local) + except ValueError as e: + sys.exit(f"Failed to parse group file '{group_local}': {e}") + + try: + tests = testfinder.find_tests(groups=groups, exclude_groups=x_groups, + tests=args.tests, + start_from=args.start_from) + if not tests: + raise ValueError('No tests selected') + except ValueError as e: + sys.exit(e) + + if args.dry_run: + print('\n'.join(tests)) + else: + with TestRunner(env, makecheck=args.makecheck, + color=args.color) as tr: + tr.run_tests([os.path.join(env.source_iotests, t) for t in tests]) diff --git a/tests/qemu-iotests/common.env.in b/tests/qemu-iotests/common.env.in deleted file mode 100644 index e565cdf40c..0000000000 --- a/tests/qemu-iotests/common.env.in +++ /dev/null @@ -1,3 +0,0 @@ -# Automatically generated by configure - do not modify - -export PYTHON='@PYTHON@' diff --git a/tests/qemu-iotests/findtests.py b/tests/qemu-iotests/findtests.py new file mode 100644 index 0000000000..dd77b453b8 --- /dev/null +++ b/tests/qemu-iotests/findtests.py @@ -0,0 +1,159 @@ +# TestFinder class, define set of tests to run. +# +# Copyright (c) 2020-2021 Virtuozzo International GmbH +# +# 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/>. +# + +import os +import glob +import re +from collections import defaultdict +from contextlib import contextmanager +from typing import Optional, List, Iterator, Set + + +@contextmanager +def chdir(path: Optional[str] = None) -> Iterator[None]: + if path is None: + yield + return + + saved_dir = os.getcwd() + os.chdir(path) + try: + yield + finally: + os.chdir(saved_dir) + + +class TestFinder: + def __init__(self, test_dir: Optional[str] = None) -> None: + self.groups = defaultdict(set) + + with chdir(test_dir): + self.all_tests = glob.glob('[0-9][0-9][0-9]') + self.all_tests += [f for f in glob.iglob('tests/*') + if not f.endswith('.out') and + os.path.isfile(f + '.out')] + + for t in self.all_tests: + with open(t, encoding="utf-8") as f: + for line in f: + if line.startswith('# group: '): + for g in line.split()[2:]: + self.groups[g].add(t) + break + + def add_group_file(self, fname: str) -> None: + with open(fname, encoding="utf-8") as f: + for line in f: + line = line.strip() + + if (not line) or line[0] == '#': + continue + + words = line.split() + test_file = self.parse_test_name(words[0]) + groups = words[1:] + + for g in groups: + self.groups[g].add(test_file) + + def parse_test_name(self, name: str) -> str: + if '/' in name: + raise ValueError('Paths are unsupported for test selection, ' + f'requiring "{name}" is wrong') + + if re.fullmatch(r'\d+', name): + # Numbered tests are old naming convention. We should convert them + # to three-digit-length, like 1 --> 001. + name = f'{int(name):03}' + else: + # Named tests all should be in tests/ subdirectory + name = os.path.join('tests', name) + + if name not in self.all_tests: + raise ValueError(f'Test "{name}" is not found') + + return name + + def find_tests(self, groups: Optional[List[str]] = None, + exclude_groups: Optional[List[str]] = None, + tests: Optional[List[str]] = None, + start_from: Optional[str] = None) -> List[str]: + """Find tests + + Algorithm: + + 1. a. if some @groups specified + a.1 Take all tests from @groups + a.2 Drop tests, which are in at least one of @exclude_groups or in + 'disabled' group (if 'disabled' is not listed in @groups) + a.3 Add tests from @tests (don't exclude anything from them) + + b. else, if some @tests specified: + b.1 exclude_groups must be not specified, so just take @tests + + c. else (only @exclude_groups list is non-empty): + c.1 Take all tests + c.2 Drop tests, which are in at least one of @exclude_groups or in + 'disabled' group + + 2. sort + + 3. If start_from specified, drop tests from first one to @start_from + (not inclusive) + """ + if groups is None: + groups = [] + if exclude_groups is None: + exclude_groups = [] + if tests is None: + tests = [] + + res: Set[str] = set() + if groups: + # Some groups specified. exclude_groups supported, additionally + # selecting some individual tests supported as well. + res.update(*(self.groups[g] for g in groups)) + elif tests: + # Some individual tests specified, but no groups. In this case + # we don't support exclude_groups. + if exclude_groups: + raise ValueError("Can't exclude from individually specified " + "tests.") + else: + # No tests no groups: start from all tests, exclude_groups + # supported. + res.update(self.all_tests) + + if 'disabled' not in groups and 'disabled' not in exclude_groups: + # Don't want to modify function argument, so create new list. + exclude_groups = exclude_groups + ['disabled'] + + res = res.difference(*(self.groups[g] for g in exclude_groups)) + + # We want to add @tests. But for compatibility with old test names, + # we should convert any number < 100 to number padded by + # leading zeroes, like 1 -> 001 and 23 -> 023. + for t in tests: + res.add(self.parse_test_name(t)) + + sequence = sorted(res) + + if start_from is not None: + del sequence[:sequence.index(self.parse_test_name(start_from))] + + return sequence diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group deleted file mode 100644 index a0d0bf1688..0000000000 --- a/tests/qemu-iotests/group +++ /dev/null @@ -1,323 +0,0 @@ -# -# QA groups control file -# Defines test groups -# -# Some notes about the groups: -# -# - do not start group names with a digit -# -# - quick : Tests in this group should finish within some few seconds. -# -# - img : Tests in this group can be used to excercise the qemu-img tool. -# -# - auto : Tests in this group are used during "make check" and should be -# runnable in any case. That means they should run with every QEMU binary -# (also non-x86), with every QEMU configuration (i.e. must not fail if -# an optional feature is not compiled in - but reporting a "skip" is ok), -# work at least with the qcow2 file format, work with all kind of host -# filesystems and users (e.g. "nobody" or "root") and must not take too -# much memory and disk space (since CI pipelines tend to fail otherwise). -# - -# -# test-group association ... one line per test -# -001 rw auto quick -002 rw auto quick -003 rw auto -004 rw auto quick -005 img auto quick -# 006 was removed, do not reuse -007 snapshot auto -008 rw auto quick -009 rw auto quick -010 rw auto quick -011 rw auto quick -012 auto quick -013 rw auto -014 rw -015 rw snapshot -# 016 was removed, do not reuse -017 rw backing auto quick -018 rw backing auto quick -019 rw backing auto quick -020 rw backing auto quick -021 io auto quick -022 rw snapshot auto -023 rw -024 rw backing auto quick -025 rw auto quick -026 rw blkdbg -027 rw auto quick -028 rw backing quick -029 rw auto quick -030 rw auto backing -031 rw auto quick -032 rw auto quick -033 rw auto quick -034 rw auto backing quick -035 rw auto quick -036 rw auto quick -037 rw auto backing quick -038 rw auto backing quick -039 rw auto quick -040 rw auto -041 rw auto backing -042 rw auto quick -043 rw auto backing -044 rw -045 rw quick -046 rw auto aio quick -047 rw auto quick -048 img auto quick -049 rw auto -050 rw auto backing quick -051 rw -052 rw auto backing quick -053 rw auto quick -054 rw auto quick -055 rw -056 rw backing -057 rw -058 rw quick -059 rw quick -060 rw auto quick -061 rw auto -062 rw auto quick -063 rw auto quick -064 rw quick -065 rw quick -066 rw auto quick -# 067 was removed, do not reuse -068 rw quick -069 rw auto quick -070 rw quick -071 rw auto quick -072 rw auto quick -073 rw auto quick -074 rw auto quick -075 rw quick -076 io -077 rw quick -078 rw quick -079 rw auto -080 rw auto -081 rw quick -082 rw quick -083 rw -084 img quick -085 rw -086 rw auto quick -087 rw quick -088 rw quick -089 rw auto quick -090 rw auto quick -091 rw migration quick -092 rw quick -093 throttle -094 rw quick -095 rw quick -096 rw quick -097 rw auto backing -098 rw auto backing quick -099 rw auto quick -# 100 was removed, do not reuse -101 rw quick -102 rw quick -103 rw auto quick -104 rw auto -105 rw auto quick -106 rw quick -107 rw auto quick -108 rw auto quick -109 rw -110 rw auto backing quick -111 rw auto quick -112 rw -113 rw quick -114 rw auto quick -115 rw -116 rw quick -117 rw auto -118 rw -119 rw quick -120 rw auto quick -121 rw -122 rw -123 rw quick -124 rw backing -125 rw -126 rw auto backing -127 rw auto backing quick -128 rw quick -129 rw quick -130 rw quick -131 rw quick -132 rw quick -133 auto quick -134 rw auto quick -135 rw -136 rw -137 rw auto -138 rw auto quick -139 rw quick -140 rw auto quick -141 rw auto quick -142 -143 auto quick -144 rw quick -145 quick -146 quick -147 img -148 rw quick -149 rw sudo -150 rw auto quick -151 rw -152 rw quick -153 rw quick -154 rw auto backing quick -155 rw -156 rw auto quick -157 quick -158 rw auto quick -159 rw auto quick -160 rw quick -161 rw auto quick -162 quick -163 rw -165 rw quick -169 rw migration -170 rw auto quick -171 rw quick -172 auto -173 rw -174 auto -175 quick -176 rw auto backing -177 rw auto quick -178 img -179 rw auto quick -181 rw auto migration quick -182 rw quick -183 rw migration quick -184 rw auto quick -185 rw -186 rw auto -187 rw auto -188 rw quick -189 rw -190 rw auto quick -191 rw auto -192 rw auto quick -194 rw migration quick -195 rw auto quick -196 rw quick migration -197 rw quick -198 rw -199 rw migration -200 rw -201 rw migration quick -202 rw quick -203 rw auto migration quick -204 rw quick -205 rw quick -206 rw -207 rw -208 rw quick -209 rw quick -210 rw -211 rw quick -212 rw quick -213 rw quick -214 rw auto -215 rw quick -216 rw quick -217 rw auto quick -218 rw quick -219 rw -220 rw auto -221 rw quick -222 rw quick -223 rw quick -224 rw quick -225 rw quick -226 auto quick -227 quick -228 rw quick -229 auto quick -231 quick -232 quick -233 quick -234 quick migration -235 quick -236 quick -237 rw quick -238 quick -239 rw quick -240 quick -241 rw quick -242 rw quick -243 rw quick -244 rw auto quick -245 rw -246 rw quick -247 rw quick -248 rw quick -249 rw auto quick -250 rw quick -251 rw auto quick -252 rw auto backing quick -253 rw quick -254 rw backing quick -255 rw quick -256 rw auto quick -257 rw -258 rw quick -259 rw auto quick -260 rw quick -261 rw -262 rw quick migration -263 rw quick -264 rw -265 rw auto quick -266 rw quick -267 rw auto quick snapshot -268 rw auto quick -270 rw backing quick -271 rw auto -272 rw -273 backing quick -274 rw backing -277 rw quick -279 rw backing quick -280 rw migration quick -281 rw quick -282 rw img quick -283 auto quick -284 rw -286 rw quick -287 auto quick -288 quick -289 rw quick -290 rw auto quick -291 rw quick -292 rw auto quick -293 rw -294 rw quick -295 rw -296 rw -297 meta -298 -299 auto quick -300 migration -301 backing quick -302 quick -303 rw quick -304 rw quick -305 rw quick -307 rw quick export -308 rw -309 rw auto quick -310 rw quick -312 rw quick -313 rw auto quick diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 335e6feb70..00be68eca3 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -1131,6 +1131,13 @@ def _verify_formats(required_formats: Sequence[str] = ()) -> None: if usf_list: notrun(f'formats {usf_list} are not whitelisted') + +def _verify_virtio_blk() -> None: + out = qemu_pipe('-M', 'none', '-device', 'help') + if 'virtio-blk' not in out: + notrun('Missing virtio-blk in QEMU binary') + + def supports_quorum(): return 'quorum' in qemu_img_pipe('--help') @@ -1308,6 +1315,7 @@ def execute_setup_common(supported_fmts: Sequence[str] = (), _verify_cache_mode(supported_cache_modes) _verify_aio_mode(supported_aio_modes) _verify_formats(required_fmts) + _verify_virtio_blk() return debug diff --git a/tests/qemu-iotests/meson.build b/tests/qemu-iotests/meson.build index 26658ce25c..67aed1e492 100644 --- a/tests/qemu-iotests/meson.build +++ b/tests/qemu-iotests/meson.build @@ -3,6 +3,3 @@ if 'CONFIG_LINUX' in config_host else socket_scm_helper = [] endif -configure_file(output: 'common.env', - input: files('common.env.in'), - configuration: {'PYTHON': python.full_path()}) diff --git a/tests/qemu-iotests/testenv.py b/tests/qemu-iotests/testenv.py new file mode 100644 index 0000000000..b31275f518 --- /dev/null +++ b/tests/qemu-iotests/testenv.py @@ -0,0 +1,281 @@ +# TestEnv class to manage test environment variables. +# +# Copyright (c) 2020-2021 Virtuozzo International GmbH +# +# 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/>. +# + +import os +import sys +import tempfile +from pathlib import Path +import shutil +import collections +import random +import subprocess +import glob +from typing import Dict, Any, Optional, ContextManager + + +def isxfile(path: str) -> bool: + return os.path.isfile(path) and os.access(path, os.X_OK) + + +def get_default_machine(qemu_prog: str) -> str: + outp = subprocess.run([qemu_prog, '-machine', 'help'], check=True, + universal_newlines=True, + stdout=subprocess.PIPE).stdout + + machines = outp.split('\n') + try: + default_machine = next(m for m in machines if m.endswith(' (default)')) + except StopIteration: + return '' + default_machine = default_machine.split(' ', 1)[0] + + alias_suf = ' (alias of {})'.format(default_machine) + alias = next((m for m in machines if m.endswith(alias_suf)), None) + if alias is not None: + default_machine = alias.split(' ', 1)[0] + + return default_machine + + +class TestEnv(ContextManager['TestEnv']): + """ + Manage system environment for running tests + + The following variables are supported/provided. They are represented by + lower-cased TestEnv attributes. + """ + + # We store environment variables as instance attributes, and there are a + # lot of them. Silence pylint: + # pylint: disable=too-many-instance-attributes + + env_variables = ['PYTHONPATH', 'TEST_DIR', 'SOCK_DIR', 'SAMPLE_IMG_DIR', + 'OUTPUT_DIR', 'PYTHON', 'QEMU_PROG', 'QEMU_IMG_PROG', + 'QEMU_IO_PROG', 'QEMU_NBD_PROG', 'QSD_PROG', + 'SOCKET_SCM_HELPER', 'QEMU_OPTIONS', 'QEMU_IMG_OPTIONS', + 'QEMU_IO_OPTIONS', 'QEMU_IO_OPTIONS_NO_FMT', + 'QEMU_NBD_OPTIONS', 'IMGOPTS', 'IMGFMT', 'IMGPROTO', + 'AIOMODE', 'CACHEMODE', 'VALGRIND_QEMU', + 'CACHEMODE_IS_DEFAULT', 'IMGFMT_GENERIC', 'IMGOPTSSYNTAX', + 'IMGKEYSECRET', 'QEMU_DEFAULT_MACHINE', 'MALLOC_PERTURB_'] + + def get_env(self) -> Dict[str, str]: + env = {} + for v in self.env_variables: + val = getattr(self, v.lower(), None) + if val is not None: + env[v] = val + + return env + + def init_directories(self) -> None: + """Init directory variables: + PYTHONPATH + TEST_DIR + SOCK_DIR + SAMPLE_IMG_DIR + OUTPUT_DIR + """ + self.pythonpath = os.getenv('PYTHONPATH') + if self.pythonpath: + self.pythonpath = self.source_iotests + os.pathsep + \ + self.pythonpath + else: + self.pythonpath = self.source_iotests + + self.test_dir = os.getenv('TEST_DIR', + os.path.join(os.getcwd(), 'scratch')) + Path(self.test_dir).mkdir(parents=True, exist_ok=True) + + try: + self.sock_dir = os.environ['SOCK_DIR'] + self.tmp_sock_dir = False + Path(self.test_dir).mkdir(parents=True, exist_ok=True) + except KeyError: + self.sock_dir = tempfile.mkdtemp() + self.tmp_sock_dir = True + + self.sample_img_dir = os.getenv('SAMPLE_IMG_DIR', + os.path.join(self.source_iotests, + 'sample_images')) + + self.output_dir = os.getcwd() # OUTPUT_DIR + + def init_binaries(self) -> None: + """Init binary path variables: + PYTHON (for bash tests) + QEMU_PROG, QEMU_IMG_PROG, QEMU_IO_PROG, QEMU_NBD_PROG, QSD_PROG + SOCKET_SCM_HELPER + """ + self.python = sys.executable + + def root(*names: str) -> str: + return os.path.join(self.build_root, *names) + + arch = os.uname().machine + if 'ppc64' in arch: + arch = 'ppc64' + + self.qemu_prog = os.getenv('QEMU_PROG', root(f'qemu-system-{arch}')) + if not os.path.exists(self.qemu_prog): + pattern = root('qemu-system-*') + try: + progs = glob.iglob(pattern) + self.qemu_prog = next(p for p in progs if isxfile(p)) + except StopIteration: + sys.exit("Not found any Qemu executable binary by pattern " + f"'{pattern}'") + + self.qemu_img_prog = os.getenv('QEMU_IMG_PROG', root('qemu-img')) + self.qemu_io_prog = os.getenv('QEMU_IO_PROG', root('qemu-io')) + self.qemu_nbd_prog = os.getenv('QEMU_NBD_PROG', root('qemu-nbd')) + self.qsd_prog = os.getenv('QSD_PROG', root('storage-daemon', + 'qemu-storage-daemon')) + + for b in [self.qemu_img_prog, self.qemu_io_prog, self.qemu_nbd_prog, + self.qemu_prog, self.qsd_prog]: + if not os.path.exists(b): + sys.exit('No such file: ' + b) + if not isxfile(b): + sys.exit('Not executable: ' + b) + + helper_path = os.path.join(self.build_iotests, 'socket_scm_helper') + if isxfile(helper_path): + self.socket_scm_helper = helper_path # SOCKET_SCM_HELPER + + def __init__(self, imgfmt: str, imgproto: str, aiomode: str, + cachemode: Optional[str] = None, + imgopts: Optional[str] = None, + misalign: bool = False, + debug: bool = False, + valgrind: bool = False) -> None: + self.imgfmt = imgfmt + self.imgproto = imgproto + self.aiomode = aiomode + self.imgopts = imgopts + self.misalign = misalign + self.debug = debug + + if valgrind: + self.valgrind_qemu = 'y' + + if cachemode is None: + self.cachemode_is_default = 'true' + self.cachemode = 'writeback' + else: + self.cachemode_is_default = 'false' + self.cachemode = cachemode + + # Initialize generic paths: build_root, build_iotests, source_iotests, + # which are needed to initialize some environment variables. They are + # used by init_*() functions as well. + + if os.path.islink(sys.argv[0]): + # called from the build tree + self.source_iotests = os.path.dirname(os.readlink(sys.argv[0])) + self.build_iotests = os.path.dirname(os.path.abspath(sys.argv[0])) + else: + # called from the source tree + self.source_iotests = os.getcwd() + self.build_iotests = self.source_iotests + + self.build_root = os.path.join(self.build_iotests, '..', '..') + + self.init_directories() + self.init_binaries() + + self.malloc_perturb_ = os.getenv('MALLOC_PERTURB_', + str(random.randrange(1, 255))) + + # QEMU_OPTIONS + self.qemu_options = '-nodefaults -display none -accel qtest' + machine_map = ( + ('arm', 'virt'), + ('aarch64', 'virt'), + ('avr', 'mega2560'), + ('rx', 'gdbsim-r5f562n8'), + ('tricore', 'tricore_testboard') + ) + for suffix, machine in machine_map: + if self.qemu_prog.endswith(f'qemu-system-{suffix}'): + self.qemu_options += f' -machine {machine}' + + # QEMU_DEFAULT_MACHINE + self.qemu_default_machine = get_default_machine(self.qemu_prog) + + self.qemu_img_options = os.getenv('QEMU_IMG_OPTIONS') + self.qemu_nbd_options = os.getenv('QEMU_NBD_OPTIONS') + + is_generic = self.imgfmt not in ['bochs', 'cloop', 'dmg'] + self.imgfmt_generic = 'true' if is_generic else 'false' + + self.qemu_io_options = f'--cache {self.cachemode} --aio {self.aiomode}' + if self.misalign: + self.qemu_io_options += ' --misalign' + + self.qemu_io_options_no_fmt = self.qemu_io_options + + if self.imgfmt == 'luks': + self.imgoptssyntax = 'true' + self.imgkeysecret = '123456' + if not self.imgopts: + self.imgopts = 'iter-time=10' + elif 'iter-time=' not in self.imgopts: + self.imgopts += ',iter-time=10' + else: + self.imgoptssyntax = 'false' + self.qemu_io_options += ' -f ' + self.imgfmt + + if self.imgfmt == 'vmdk': + if not self.imgopts: + self.imgopts = 'zeroed_grain=on' + elif 'zeroed_grain=' not in self.imgopts: + self.imgopts += ',zeroed_grain=on' + + def close(self) -> None: + if self.tmp_sock_dir: + shutil.rmtree(self.sock_dir) + + def __enter__(self) -> 'TestEnv': + return self + + def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None: + self.close() + + def print_env(self) -> None: + template = """\ +QEMU -- "{QEMU_PROG}" {QEMU_OPTIONS} +QEMU_IMG -- "{QEMU_IMG_PROG}" {QEMU_IMG_OPTIONS} +QEMU_IO -- "{QEMU_IO_PROG}" {QEMU_IO_OPTIONS} +QEMU_NBD -- "{QEMU_NBD_PROG}" {QEMU_NBD_OPTIONS} +IMGFMT -- {IMGFMT}{imgopts} +IMGPROTO -- {IMGPROTO} +PLATFORM -- {platform} +TEST_DIR -- {TEST_DIR} +SOCK_DIR -- {SOCK_DIR} +SOCKET_SCM_HELPER -- {SOCKET_SCM_HELPER}""" + + args = collections.defaultdict(str, self.get_env()) + + if 'IMGOPTS' in args: + args['imgopts'] = f" ({args['IMGOPTS']})" + + u = os.uname() + args['platform'] = f'{u.sysname}/{u.machine} {u.nodename} {u.release}' + + print(template.format_map(args)) diff --git a/tests/qemu-iotests/testrunner.py b/tests/qemu-iotests/testrunner.py new file mode 100644 index 0000000000..a581be6a29 --- /dev/null +++ b/tests/qemu-iotests/testrunner.py @@ -0,0 +1,367 @@ +# Class for actually running tests. +# +# Copyright (c) 2020-2021 Virtuozzo International GmbH +# +# 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/>. +# + +import os +from pathlib import Path +import datetime +import time +import difflib +import subprocess +import contextlib +import json +import termios +import sys +from contextlib import contextmanager +from typing import List, Optional, Iterator, Any, Sequence, Dict, \ + ContextManager + +from testenv import TestEnv + + +def silent_unlink(path: Path) -> None: + try: + path.unlink() + except OSError: + pass + + +def file_diff(file1: str, file2: str) -> List[str]: + with open(file1, encoding="utf-8") as f1, \ + open(file2, encoding="utf-8") as f2: + # We want to ignore spaces at line ends. There are a lot of mess about + # it in iotests. + # TODO: fix all tests to not produce extra spaces, fix all .out files + # and use strict diff here! + seq1 = [line.rstrip() for line in f1] + seq2 = [line.rstrip() for line in f2] + res = [line.rstrip() + for line in difflib.unified_diff(seq1, seq2, file1, file2)] + return res + + +# We want to save current tty settings during test run, +# since an aborting qemu call may leave things screwed up. +@contextmanager +def savetty() -> Iterator[None]: + isterm = sys.stdin.isatty() + if isterm: + fd = sys.stdin.fileno() + attr = termios.tcgetattr(fd) + + try: + yield + finally: + if isterm: + termios.tcsetattr(fd, termios.TCSADRAIN, attr) + + +class LastElapsedTime(ContextManager['LastElapsedTime']): + """ Cache for elapsed time for tests, to show it during new test run + + It is safe to use get() at any time. To use update(), you must either + use it inside with-block or use save() after update(). + """ + def __init__(self, cache_file: str, env: TestEnv) -> None: + self.env = env + self.cache_file = cache_file + self.cache: Dict[str, Dict[str, Dict[str, float]]] + + try: + with open(cache_file, encoding="utf-8") as f: + self.cache = json.load(f) + except (OSError, ValueError): + self.cache = {} + + def get(self, test: str, + default: Optional[float] = None) -> Optional[float]: + if test not in self.cache: + return default + + if self.env.imgproto not in self.cache[test]: + return default + + return self.cache[test][self.env.imgproto].get(self.env.imgfmt, + default) + + def update(self, test: str, elapsed: float) -> None: + d = self.cache.setdefault(test, {}) + d.setdefault(self.env.imgproto, {})[self.env.imgfmt] = elapsed + + def save(self) -> None: + with open(self.cache_file, 'w', encoding="utf-8") as f: + json.dump(self.cache, f) + + def __enter__(self) -> 'LastElapsedTime': + return self + + def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None: + self.save() + + +class TestResult: + def __init__(self, status: str, description: str = '', + elapsed: Optional[float] = None, diff: Sequence[str] = (), + casenotrun: str = '', interrupted: bool = False) -> None: + self.status = status + self.description = description + self.elapsed = elapsed + self.diff = diff + self.casenotrun = casenotrun + self.interrupted = interrupted + + +class TestRunner(ContextManager['TestRunner']): + def __init__(self, env: TestEnv, makecheck: bool = False, + color: str = 'auto') -> None: + self.env = env + self.test_run_env = self.env.get_env() + self.makecheck = makecheck + self.last_elapsed = LastElapsedTime('.last-elapsed-cache', env) + + assert color in ('auto', 'on', 'off') + self.color = (color == 'on') or (color == 'auto' and + sys.stdout.isatty()) + + self._stack: contextlib.ExitStack + + def __enter__(self) -> 'TestRunner': + self._stack = contextlib.ExitStack() + self._stack.enter_context(self.env) + self._stack.enter_context(self.last_elapsed) + self._stack.enter_context(savetty()) + return self + + def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None: + self._stack.close() + + def test_print_one_line(self, test: str, starttime: str, + endtime: Optional[str] = None, status: str = '...', + lasttime: Optional[float] = None, + thistime: Optional[float] = None, + description: str = '', + test_field_width: Optional[int] = None, + end: str = '\n') -> None: + """ Print short test info before/after test run """ + test = os.path.basename(test) + + if test_field_width is None: + test_field_width = 8 + + if self.makecheck and status != '...': + if status and status != 'pass': + status = f' [{status}]' + else: + status = '' + + print(f' TEST iotest-{self.env.imgfmt}: {test}{status}') + return + + if lasttime: + lasttime_s = f' (last: {lasttime:.1f}s)' + else: + lasttime_s = '' + if thistime: + thistime_s = f'{thistime:.1f}s' + else: + thistime_s = '...' + + if endtime: + endtime = f'[{endtime}]' + else: + endtime = '' + + if self.color: + if status == 'pass': + col = '\033[32m' + elif status == 'fail': + col = '\033[1m\033[31m' + elif status == 'not run': + col = '\033[33m' + else: + col = '' + + col_end = '\033[0m' + else: + col = '' + col_end = '' + + print(f'{test:{test_field_width}} {col}{status:10}{col_end} ' + f'[{starttime}] {endtime:13}{thistime_s:5} {lasttime_s:14} ' + f'{description}', end=end) + + def find_reference(self, test: str) -> str: + if self.env.cachemode == 'none': + ref = f'{test}.out.nocache' + if os.path.isfile(ref): + return ref + + ref = f'{test}.out.{self.env.imgfmt}' + if os.path.isfile(ref): + return ref + + ref = f'{test}.{self.env.qemu_default_machine}.out' + if os.path.isfile(ref): + return ref + + return f'{test}.out' + + def do_run_test(self, test: str) -> TestResult: + f_test = Path(test) + f_bad = Path(f_test.name + '.out.bad') + f_notrun = Path(f_test.name + '.notrun') + f_casenotrun = Path(f_test.name + '.casenotrun') + f_reference = Path(self.find_reference(test)) + + if not f_test.exists(): + return TestResult(status='fail', + description=f'No such test file: {f_test}') + + if not os.access(str(f_test), os.X_OK): + sys.exit(f'Not executable: {f_test}') + + if not f_reference.exists(): + return TestResult(status='not run', + description='No qualified output ' + f'(expected {f_reference})') + + for p in (f_bad, f_notrun, f_casenotrun): + silent_unlink(p) + + args = [str(f_test.resolve())] + if self.env.debug: + args.append('-d') + + with f_test.open(encoding="utf-8") as f: + try: + if f.readline() == '#!/usr/bin/env python3': + args.insert(0, self.env.python) + except UnicodeDecodeError: # binary test? for future. + pass + + env = os.environ.copy() + env.update(self.test_run_env) + + t0 = time.time() + with f_bad.open('w', encoding="utf-8") as f: + proc = subprocess.Popen(args, cwd=str(f_test.parent), env=env, + stdout=f, stderr=subprocess.STDOUT) + try: + proc.wait() + except KeyboardInterrupt: + proc.terminate() + proc.wait() + return TestResult(status='not run', + description='Interrupted by user', + interrupted=True) + ret = proc.returncode + + elapsed = round(time.time() - t0, 1) + + if ret != 0: + return TestResult(status='fail', elapsed=elapsed, + description=f'failed, exit status {ret}', + diff=file_diff(str(f_reference), str(f_bad))) + + if f_notrun.exists(): + return TestResult(status='not run', + description=f_notrun.read_text().strip()) + + casenotrun = '' + if f_casenotrun.exists(): + casenotrun = f_casenotrun.read_text() + + diff = file_diff(str(f_reference), str(f_bad)) + if diff: + return TestResult(status='fail', elapsed=elapsed, + description=f'output mismatch (see {f_bad})', + diff=diff, casenotrun=casenotrun) + else: + f_bad.unlink() + self.last_elapsed.update(test, elapsed) + return TestResult(status='pass', elapsed=elapsed, + casenotrun=casenotrun) + + def run_test(self, test: str, + test_field_width: Optional[int] = None) -> TestResult: + last_el = self.last_elapsed.get(test) + start = datetime.datetime.now().strftime('%H:%M:%S') + + self.test_print_one_line(test=test, starttime=start, lasttime=last_el, + end='\r', test_field_width=test_field_width) + + res = self.do_run_test(test) + + end = datetime.datetime.now().strftime('%H:%M:%S') + self.test_print_one_line(test=test, status=res.status, + starttime=start, endtime=end, + lasttime=last_el, thistime=res.elapsed, + description=res.description, + test_field_width=test_field_width) + + if res.casenotrun: + print(res.casenotrun) + + return res + + def run_tests(self, tests: List[str]) -> None: + n_run = 0 + failed = [] + notrun = [] + casenotrun = [] + + if not self.makecheck: + self.env.print_env() + print() + + test_field_width = max(len(os.path.basename(t)) for t in tests) + 2 + + for t in tests: + name = os.path.basename(t) + res = self.run_test(t, test_field_width=test_field_width) + + assert res.status in ('pass', 'fail', 'not run') + + if res.casenotrun: + casenotrun.append(t) + + if res.status != 'not run': + n_run += 1 + + if res.status == 'fail': + failed.append(name) + if self.makecheck: + self.env.print_env() + if res.diff: + print('\n'.join(res.diff)) + elif res.status == 'not run': + notrun.append(name) + + if res.interrupted: + break + + if notrun: + print('Not run:', ' '.join(notrun)) + + if casenotrun: + print('Some cases not run in:', ' '.join(casenotrun)) + + if failed: + print('Failures:', ' '.join(failed)) + print(f'Failed {len(failed)} of {n_run} iotests') + else: + print(f'Passed all {n_run} iotests') diff --git a/tests/qemu-iotests/199 b/tests/qemu-iotests/tests/migrate-bitmaps-postcopy-test index dbf10e58d3..dbf10e58d3 100755 --- a/tests/qemu-iotests/199 +++ b/tests/qemu-iotests/tests/migrate-bitmaps-postcopy-test diff --git a/tests/qemu-iotests/199.out b/tests/qemu-iotests/tests/migrate-bitmaps-postcopy-test.out index 8d7e996700..8d7e996700 100644 --- a/tests/qemu-iotests/199.out +++ b/tests/qemu-iotests/tests/migrate-bitmaps-postcopy-test.out diff --git a/tests/qemu-iotests/169 b/tests/qemu-iotests/tests/migrate-bitmaps-test index a5c7bc83e0..a5c7bc83e0 100755 --- a/tests/qemu-iotests/169 +++ b/tests/qemu-iotests/tests/migrate-bitmaps-test diff --git a/tests/qemu-iotests/169.out b/tests/qemu-iotests/tests/migrate-bitmaps-test.out index cafb8161f7..cafb8161f7 100644 --- a/tests/qemu-iotests/169.out +++ b/tests/qemu-iotests/tests/migrate-bitmaps-test.out diff --git a/tests/qtest/virtio-scsi-test.c b/tests/qtest/virtio-scsi-test.c index 0415e75876..1b7ecc1c8f 100644 --- a/tests/qtest/virtio-scsi-test.c +++ b/tests/qtest/virtio-scsi-test.c @@ -200,6 +200,32 @@ static void test_unaligned_write_same(void *obj, void *data, qvirtio_scsi_pci_free(vs); } +static void test_write_to_cdrom(void *obj, void *data, + QGuestAllocator *t_alloc) +{ + QVirtioSCSI *scsi = obj; + QVirtioSCSIQueues *vs; + uint8_t buf[2048] = { 0 }; + const uint8_t write_cdb[VIRTIO_SCSI_CDB_SIZE] = { + /* WRITE(10) to LBA 0, transfer length 1 */ + 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00 + }; + struct virtio_scsi_cmd_resp resp; + + alloc = t_alloc; + vs = qvirtio_scsi_init(scsi->vdev); + + virtio_scsi_do_command(vs, write_cdb, NULL, 0, buf, 2048, &resp); + g_assert_cmphex(resp.response, ==, 0); + g_assert_cmphex(resp.status, ==, CHECK_CONDITION); + g_assert_cmphex(resp.sense[0], ==, 0x70); + g_assert_cmphex(resp.sense[2], ==, DATA_PROTECT); + g_assert_cmphex(resp.sense[12], ==, 0x27); /* WRITE PROTECTED */ + g_assert_cmphex(resp.sense[13], ==, 0x00); /* WRITE PROTECTED */ + + qvirtio_scsi_pci_free(vs); +} + static void test_iothread_attach_node(void *obj, void *data, QGuestAllocator *t_alloc) { @@ -267,6 +293,16 @@ static void *virtio_scsi_setup(GString *cmd_line, void *arg) return arg; } +static void *virtio_scsi_setup_cd(GString *cmd_line, void *arg) +{ + g_string_append(cmd_line, + " -drive file=null-co://," + "file.read-zeroes=on," + "if=none,id=dr1,format=raw " + "-device scsi-cd,drive=dr1,lun=0,scsi-id=1"); + return arg; +} + static void *virtio_scsi_setup_iothread(GString *cmd_line, void *arg) { g_string_append(cmd_line, @@ -287,6 +323,9 @@ static void register_virtio_scsi_test(void) qos_add_test("unaligned-write-same", "virtio-scsi", test_unaligned_write_same, &opts); + opts.before = virtio_scsi_setup_cd; + qos_add_test("write-to-cdrom", "virtio-scsi", test_write_to_cdrom, &opts); + opts.before = virtio_scsi_setup_iothread; opts.edge = (QOSGraphEdgeOptions) { .extra_device_opts = "iothread=thread0", |