From: Peter Krempa <[email protected]>

Add code which walks the generated argument list and allows to strip out
and replace by a substitution any field in either JSON or legacy qemu
argument string.

Use it to stabilize 'fd' field of '-add-fd'

This will allow us to rip out code which tries to allocate stable FD
numbers, which doesn't work reliably (e.g. if the environment passes
some FDs).

Signed-off-by: Peter Krempa <[email protected]>
---
 .../aarch64-pci-serial.aarch64-latest.args    |   2 +-
 .../chardev-backends-json.x86_64-9.1.0.args   |   6 +-
 .../chardev-backends-json.x86_64-latest.args  |   6 +-
 .../chardev-backends.x86_64-9.1.0.args        |   6 +-
 .../chardev-backends.x86_64-latest.args       |   6 +-
 .../chardev-label.x86_64-latest.args          |   2 +-
 .../disk-source-fd.x86_64-latest.args         |  16 +-
 .../disk-vhostvdpa.x86_64-latest.args         |   2 +-
 .../name-escape.x86_64-latest.args            |   2 +-
 .../net-vdpa-multiqueue.x86_64-latest.args    |   2 +-
 .../net-vdpa.x86_64-latest.args               |   2 +-
 .../serial-file-chardev.x86_64-latest.args    |   2 +-
 .../serial-file-log.x86_64-latest.args        |   4 +-
 .../serial-many-chardev.x86_64-latest.args    |   2 +-
 .../tpm-passthrough-crb.x86_64-latest.args    |   4 +-
 .../tpm-passthrough.x86_64-latest.args        |   4 +-
 tests/qemuxmlconftest.c                       | 193 ++++++++++++++++++
 tests/testutilsqemu.h                         |   2 +
 18 files changed, 229 insertions(+), 34 deletions(-)

diff --git a/tests/qemuxmlconfdata/aarch64-pci-serial.aarch64-latest.args 
b/tests/qemuxmlconfdata/aarch64-pci-serial.aarch64-latest.args
index d90e4cba18..9d3cf39d6a 100644
--- a/tests/qemuxmlconfdata/aarch64-pci-serial.aarch64-latest.args
+++ b/tests/qemuxmlconfdata/aarch64-pci-serial.aarch64-latest.args
@@ -28,7 +28,7 @@ 
XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-aarch64test/.config \
 -device 
'{"driver":"pcie-root-port","port":8,"chassis":1,"id":"pci.1","bus":"pcie.0","multifunction":true,"addr":"0x1"}'
 \
 -device '{"driver":"pcie-pci-bridge","id":"pci.2","bus":"pci.1","addr":"0x0"}' 
\
 -device 
'{"driver":"pcie-root-port","port":9,"chassis":3,"id":"pci.3","bus":"pcie.0","addr":"0x1.0x1"}'
 \
--add-fd set=0,fd=1751,opaque=serial0-log \
+-add-fd set=0,fd=XXXXXXX,opaque=serial0-log \
 -chardev pty,id=charserial0,logfile=/dev/fdset/0,logappend=on \
 -device 
'{"driver":"pci-serial","chardev":"charserial0","id":"serial0","bus":"pci.2","addr":"0x1"}'
 \
 -audiodev '{"id":"audio1","driver":"none"}' \
diff --git a/tests/qemuxmlconfdata/chardev-backends-json.x86_64-9.1.0.args 
b/tests/qemuxmlconfdata/chardev-backends-json.x86_64-9.1.0.args
index dce4a582d2..a363549b81 100644
--- a/tests/qemuxmlconfdata/chardev-backends-json.x86_64-9.1.0.args
+++ b/tests/qemuxmlconfdata/chardev-backends-json.x86_64-9.1.0.args
@@ -29,17 +29,17 @@ 
XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.config \
 -device 
'{"driver":"virtio-serial-pci","id":"virtio-serial0","bus":"pci.0","addr":"0x3"}'
 \
 -chardev 
'{"id":"charparallel0","backend":{"type":"parallel","data":{"device":"/dev/parport0"}}}'
 \
 -device '{"driver":"isa-parallel","chardev":"charparallel0","id":"parallel0"}' 
\
--add-fd set=0,fd=1751,opaque=channel0-log \
+-add-fd set=0,fd=XXXXXXX,opaque=channel0-log \
 -chardev 
'{"id":"charchannel0","backend":{"type":"null","data":{"logfile":"/dev/fdset/0","logappend":true}}}'
 \
 -device 
'{"driver":"virtserialport","bus":"virtio-serial0.0","nr":1,"chardev":"charchannel0","id":"channel0","name":"chardev-null"}'
 \
--add-fd set=1,fd=1751,opaque=channel1-log \
+-add-fd set=1,fd=XXXXXXX,opaque=channel1-log \
 -chardev 
'{"id":"charchannel1","backend":{"type":"vc","data":{"logfile":"/dev/fdset/1","logappend":true}}}'
 \
 -device 
'{"driver":"virtserialport","bus":"virtio-serial0.0","nr":2,"chardev":"charchannel1","id":"channel1","name":"chardev-vc"}'
 \
 -chardev '{"id":"charchannel2","backend":{"type":"pty","data":{}}}' \
 -device 
'{"driver":"virtserialport","bus":"virtio-serial0.0","nr":3,"chardev":"charchannel2","id":"channel2","name":"chardev-pty"}'
 \
 -chardev '{"id":"charchannel3","backend":{"type":"stdio","data":{}}}' \
 -device 
'{"driver":"virtserialport","bus":"virtio-serial0.0","nr":4,"chardev":"charchannel3","id":"channel3","name":"chardev-stdio"}'
 \
--add-fd set=2,fd=1750,opaque=channel4-source \
+-add-fd set=2,fd=XXXXXXX,opaque=channel4-source \
 -chardev 
'{"id":"charchannel4","backend":{"type":"file","data":{"out":"/dev/fdset/2","append":true}}}'
 \
 -device 
'{"driver":"virtserialport","bus":"virtio-serial0.0","nr":5,"chardev":"charchannel4","id":"channel4","name":"chardev-file"}'
 \
 -chardev 
'{"id":"charchannel5","backend":{"type":"pipe","data":{"device":"/path/to/pipe"}}}'
 \
diff --git a/tests/qemuxmlconfdata/chardev-backends-json.x86_64-latest.args 
b/tests/qemuxmlconfdata/chardev-backends-json.x86_64-latest.args
index 2b7e614e8b..43a56f7c22 100644
--- a/tests/qemuxmlconfdata/chardev-backends-json.x86_64-latest.args
+++ b/tests/qemuxmlconfdata/chardev-backends-json.x86_64-latest.args
@@ -29,17 +29,17 @@ 
XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.config \
 -device 
'{"driver":"virtio-serial-pci","id":"virtio-serial0","bus":"pci.0","addr":"0x3"}'
 \
 -chardev 
'{"id":"charparallel0","backend":{"type":"parallel","data":{"device":"/dev/parport0"}}}'
 \
 -device '{"driver":"isa-parallel","chardev":"charparallel0","id":"parallel0"}' 
\
--add-fd set=0,fd=1751,opaque=channel0-log \
+-add-fd set=0,fd=XXXXXXX,opaque=channel0-log \
 -chardev 
'{"id":"charchannel0","backend":{"type":"null","data":{"logfile":"/dev/fdset/0","logappend":true}}}'
 \
 -device 
'{"driver":"virtserialport","bus":"virtio-serial0.0","nr":1,"chardev":"charchannel0","id":"channel0","name":"chardev-null"}'
 \
--add-fd set=1,fd=1751,opaque=channel1-log \
+-add-fd set=1,fd=XXXXXXX,opaque=channel1-log \
 -chardev 
'{"id":"charchannel1","backend":{"type":"vc","data":{"logfile":"/dev/fdset/1","logappend":true}}}'
 \
 -device 
'{"driver":"virtserialport","bus":"virtio-serial0.0","nr":2,"chardev":"charchannel1","id":"channel1","name":"chardev-vc"}'
 \
 -chardev '{"id":"charchannel2","backend":{"type":"pty","data":{}}}' \
 -device 
'{"driver":"virtserialport","bus":"virtio-serial0.0","nr":3,"chardev":"charchannel2","id":"channel2","name":"chardev-pty"}'
 \
 -chardev '{"id":"charchannel3","backend":{"type":"stdio","data":{}}}' \
 -device 
'{"driver":"virtserialport","bus":"virtio-serial0.0","nr":4,"chardev":"charchannel3","id":"channel3","name":"chardev-stdio"}'
 \
--add-fd set=2,fd=1750,opaque=channel4-source \
+-add-fd set=2,fd=XXXXXXX,opaque=channel4-source \
 -chardev 
'{"id":"charchannel4","backend":{"type":"file","data":{"out":"/dev/fdset/2","append":true}}}'
 \
 -device 
'{"driver":"virtserialport","bus":"virtio-serial0.0","nr":5,"chardev":"charchannel4","id":"channel4","name":"chardev-file"}'
 \
 -chardev 
'{"id":"charchannel5","backend":{"type":"pipe","data":{"device":"/path/to/pipe"}}}'
 \
diff --git a/tests/qemuxmlconfdata/chardev-backends.x86_64-9.1.0.args 
b/tests/qemuxmlconfdata/chardev-backends.x86_64-9.1.0.args
index 81773dcacd..4d8511a95f 100644
--- a/tests/qemuxmlconfdata/chardev-backends.x86_64-9.1.0.args
+++ b/tests/qemuxmlconfdata/chardev-backends.x86_64-9.1.0.args
@@ -29,17 +29,17 @@ 
XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.config \
 -device 
'{"driver":"virtio-serial-pci","id":"virtio-serial0","bus":"pci.0","addr":"0x3"}'
 \
 -chardev parallel,id=charparallel0,path=/dev/parport0 \
 -device '{"driver":"isa-parallel","chardev":"charparallel0","id":"parallel0"}' 
\
--add-fd set=0,fd=1751,opaque=channel0-log \
+-add-fd set=0,fd=XXXXXXX,opaque=channel0-log \
 -chardev null,id=charchannel0,logfile=/dev/fdset/0,logappend=on \
 -device 
'{"driver":"virtserialport","bus":"virtio-serial0.0","nr":1,"chardev":"charchannel0","id":"channel0","name":"chardev-null"}'
 \
--add-fd set=1,fd=1751,opaque=channel1-log \
+-add-fd set=1,fd=XXXXXXX,opaque=channel1-log \
 -chardev vc,id=charchannel1,logfile=/dev/fdset/1,logappend=on \
 -device 
'{"driver":"virtserialport","bus":"virtio-serial0.0","nr":2,"chardev":"charchannel1","id":"channel1","name":"chardev-vc"}'
 \
 -chardev pty,id=charchannel2 \
 -device 
'{"driver":"virtserialport","bus":"virtio-serial0.0","nr":3,"chardev":"charchannel2","id":"channel2","name":"chardev-pty"}'
 \
 -chardev stdio,id=charchannel3 \
 -device 
'{"driver":"virtserialport","bus":"virtio-serial0.0","nr":4,"chardev":"charchannel3","id":"channel3","name":"chardev-stdio"}'
 \
--add-fd set=2,fd=1750,opaque=channel4-source \
+-add-fd set=2,fd=XXXXXXX,opaque=channel4-source \
 -chardev file,id=charchannel4,path=/dev/fdset/2,append=on \
 -device 
'{"driver":"virtserialport","bus":"virtio-serial0.0","nr":5,"chardev":"charchannel4","id":"channel4","name":"chardev-file"}'
 \
 -chardev pipe,id=charchannel5,path=/path/to/pipe \
diff --git a/tests/qemuxmlconfdata/chardev-backends.x86_64-latest.args 
b/tests/qemuxmlconfdata/chardev-backends.x86_64-latest.args
index 9708b18735..bd5af10bb7 100644
--- a/tests/qemuxmlconfdata/chardev-backends.x86_64-latest.args
+++ b/tests/qemuxmlconfdata/chardev-backends.x86_64-latest.args
@@ -29,17 +29,17 @@ 
XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.config \
 -device 
'{"driver":"virtio-serial-pci","id":"virtio-serial0","bus":"pci.0","addr":"0x3"}'
 \
 -chardev parallel,id=charparallel0,path=/dev/parport0 \
 -device '{"driver":"isa-parallel","chardev":"charparallel0","id":"parallel0"}' 
\
--add-fd set=0,fd=1751,opaque=channel0-log \
+-add-fd set=0,fd=XXXXXXX,opaque=channel0-log \
 -chardev null,id=charchannel0,logfile=/dev/fdset/0,logappend=on \
 -device 
'{"driver":"virtserialport","bus":"virtio-serial0.0","nr":1,"chardev":"charchannel0","id":"channel0","name":"chardev-null"}'
 \
--add-fd set=1,fd=1751,opaque=channel1-log \
+-add-fd set=1,fd=XXXXXXX,opaque=channel1-log \
 -chardev vc,id=charchannel1,logfile=/dev/fdset/1,logappend=on \
 -device 
'{"driver":"virtserialport","bus":"virtio-serial0.0","nr":2,"chardev":"charchannel1","id":"channel1","name":"chardev-vc"}'
 \
 -chardev pty,id=charchannel2 \
 -device 
'{"driver":"virtserialport","bus":"virtio-serial0.0","nr":3,"chardev":"charchannel2","id":"channel2","name":"chardev-pty"}'
 \
 -chardev stdio,id=charchannel3 \
 -device 
'{"driver":"virtserialport","bus":"virtio-serial0.0","nr":4,"chardev":"charchannel3","id":"channel3","name":"chardev-stdio"}'
 \
--add-fd set=2,fd=1750,opaque=channel4-source \
+-add-fd set=2,fd=XXXXXXX,opaque=channel4-source \
 -chardev file,id=charchannel4,path=/dev/fdset/2,append=on \
 -device 
'{"driver":"virtserialport","bus":"virtio-serial0.0","nr":5,"chardev":"charchannel4","id":"channel4","name":"chardev-file"}'
 \
 -chardev pipe,id=charchannel5,path=/path/to/pipe \
diff --git a/tests/qemuxmlconfdata/chardev-label.x86_64-latest.args 
b/tests/qemuxmlconfdata/chardev-label.x86_64-latest.args
index 9e54c0f7f3..b3c79cfd18 100644
--- a/tests/qemuxmlconfdata/chardev-label.x86_64-latest.args
+++ b/tests/qemuxmlconfdata/chardev-label.x86_64-latest.args
@@ -27,7 +27,7 @@ 
XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-machine/.config \
 -no-shutdown \
 -boot strict=on \
 -device 
'{"driver":"piix3-usb-uhci","id":"usb","bus":"pci.0","addr":"0x1.0x2"}' \
--add-fd set=0,fd=1750,opaque=serial0-source \
+-add-fd set=0,fd=XXXXXXX,opaque=serial0-source \
 -chardev file,id=charserial0,path=/dev/fdset/0,append=on \
 -device 
'{"driver":"isa-serial","chardev":"charserial0","id":"serial0","index":0}' \
 -chardev socket,id=charserial1,path=/tmp/serial.sock \
diff --git a/tests/qemuxmlconfdata/disk-source-fd.x86_64-latest.args 
b/tests/qemuxmlconfdata/disk-source-fd.x86_64-latest.args
index 27d852cf32..148fe74233 100644
--- a/tests/qemuxmlconfdata/disk-source-fd.x86_64-latest.args
+++ b/tests/qemuxmlconfdata/disk-source-fd.x86_64-latest.args
@@ -27,26 +27,26 @@ 
XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.config \
 -no-shutdown \
 -boot strict=on \
 -device 
'{"driver":"piix3-usb-uhci","id":"usb","bus":"pci.0","addr":"0x1.0x2"}' \
--add-fd set=5,fd=200,opaque=libvirt-6-storage0 \
--add-fd set=5,fd=205,opaque=libvirt-6-storage1 \
+-add-fd set=5,fd=XXXXXXX,opaque=libvirt-6-storage0 \
+-add-fd set=5,fd=XXXXXXX,opaque=libvirt-6-storage1 \
 -blockdev 
'{"driver":"file","filename":"/dev/fdset/5","node-name":"libvirt-6-storage","auto-read-only":true,"discard":"unmap"}'
 \
 -blockdev 
'{"node-name":"libvirt-6-format","read-only":false,"driver":"qcow2","file":"libvirt-6-storage"}'
 \
 -device 
'{"driver":"virtio-blk-pci","bus":"pci.0","addr":"0x2","drive":"libvirt-6-format","id":"virtio-disk4","bootindex":1}'
 \
--add-fd set=4,fd=209,opaque=libvirt-5-storage0 \
+-add-fd set=4,fd=XXXXXXX,opaque=libvirt-5-storage0 \
 -blockdev 
'{"driver":"file","filename":"/dev/fdset/4","node-name":"libvirt-5-storage","read-only":false,"discard":"unmap"}'
 \
 -blockdev 
'{"node-name":"libvirt-5-format","read-only":true,"driver":"raw","file":"libvirt-5-storage"}'
 \
--add-fd set=3,fd=247,opaque=libvirt-4-storage0 \
--add-fd set=3,fd=248,opaque=libvirt-4-storage1 \
+-add-fd set=3,fd=XXXXXXX,opaque=libvirt-4-storage0 \
+-add-fd set=3,fd=XXXXXXX,opaque=libvirt-4-storage1 \
 -blockdev 
'{"driver":"file","filename":"/dev/fdset/3","node-name":"libvirt-4-storage","auto-read-only":true,"discard":"unmap"}'
 \
 -blockdev 
'{"node-name":"libvirt-4-format","read-only":true,"driver":"qcow2","file":"libvirt-4-storage","backing":"libvirt-5-format"}'
 \
--add-fd set=2,fd=204,opaque=libvirt-3-storage0 \
+-add-fd set=2,fd=XXXXXXX,opaque=libvirt-3-storage0 \
 -blockdev 
'{"driver":"file","filename":"/dev/fdset/2","node-name":"libvirt-3-storage","read-only":false,"discard":"unmap"}'
 \
 -blockdev 
'{"node-name":"libvirt-3-format","read-only":false,"driver":"qcow2","file":"libvirt-3-storage","backing":"libvirt-4-format"}'
 \
 -device 
'{"driver":"virtio-blk-pci","bus":"pci.0","addr":"0x3","drive":"libvirt-3-format","id":"virtio-disk5"}'
 \
--add-fd set=1,fd=207,opaque=libvirt-2-storage0 \
+-add-fd set=1,fd=XXXXXXX,opaque=libvirt-2-storage0 \
 -blockdev 
'{"driver":"file","filename":"/dev/fdset/1","node-name":"libvirt-2-storage","read-only":true}'
 \
 -device 
'{"driver":"ide-cd","bus":"ide.0","unit":0,"drive":"libvirt-2-storage","id":"ide0-0-0"}'
 \
--add-fd set=0,fd=208,opaque=libvirt-1-storage0 \
+-add-fd set=0,fd=XXXXXXX,opaque=libvirt-1-storage0 \
 -blockdev 
'{"driver":"file","filename":"/dev/fdset/0","node-name":"libvirt-1-storage","read-only":false,"discard":"unmap"}'
 \
 -blockdev 
'{"node-name":"libvirt-1-format","read-only":true,"driver":"raw","file":"libvirt-1-storage"}'
 \
 -device 
'{"driver":"ide-cd","bus":"ide.0","unit":1,"drive":"libvirt-1-format","id":"ide0-0-1"}'
 \
diff --git a/tests/qemuxmlconfdata/disk-vhostvdpa.x86_64-latest.args 
b/tests/qemuxmlconfdata/disk-vhostvdpa.x86_64-latest.args
index 93d2ef0d98..f52fcd2eb0 100644
--- a/tests/qemuxmlconfdata/disk-vhostvdpa.x86_64-latest.args
+++ b/tests/qemuxmlconfdata/disk-vhostvdpa.x86_64-latest.args
@@ -27,7 +27,7 @@ 
XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.config \
 -no-shutdown \
 -boot strict=on \
 -device 
'{"driver":"piix3-usb-uhci","id":"usb","bus":"pci.0","addr":"0x1.0x2"}' \
--add-fd set=0,fd=201,opaque=libvirt-1-storage-vdpa \
+-add-fd set=0,fd=XXXXXXX,opaque=libvirt-1-storage-vdpa \
 -blockdev 
'{"driver":"virtio-blk-vhost-vdpa","path":"/dev/fdset/0","node-name":"libvirt-1-storage","read-only":false,"cache":{"direct":true,"no-flush":false}}'
 \
 -device 
'{"driver":"virtio-blk-pci","bus":"pci.0","addr":"0x2","drive":"libvirt-1-storage","id":"virtio-disk0","bootindex":1,"write-cache":"on"}'
 \
 -audiodev '{"id":"audio1","driver":"none"}' \
diff --git a/tests/qemuxmlconfdata/name-escape.x86_64-latest.args 
b/tests/qemuxmlconfdata/name-escape.x86_64-latest.args
index 9eec8f5a9f..6a7032d99a 100644
--- a/tests/qemuxmlconfdata/name-escape.x86_64-latest.args
+++ b/tests/qemuxmlconfdata/name-escape.x86_64-latest.args
@@ -34,7 +34,7 @@ 
XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-foo=1,bar=2/.config \
 -device 
'{"driver":"ccid-card-emulated","backend":"certificates","cert1":"cert1,foo","cert2":"cert2","cert3":"cert3","db":"/etc/pki/nssdb,foo","id":"smartcard0","bus":"ccid0.0"}'
 \
 -chardev serial,id=charserial0,path=/dev/ttyS2,,foo \
 -device 
'{"driver":"isa-serial","chardev":"charserial0","id":"serial0","index":1}' \
--add-fd set=0,fd=1750,opaque=serial1-source \
+-add-fd set=0,fd=XXXXXXX,opaque=serial1-source \
 -chardev file,id=charserial1,path=/dev/fdset/0,append=on \
 -device 
'{"driver":"isa-serial","chardev":"charserial1","id":"serial1","index":0}' \
 -chardev pipe,id=charchannel0,path=/tmp/guestfwd,,foo \
diff --git a/tests/qemuxmlconfdata/net-vdpa-multiqueue.x86_64-latest.args 
b/tests/qemuxmlconfdata/net-vdpa-multiqueue.x86_64-latest.args
index e3aee785bf..313627eab0 100644
--- a/tests/qemuxmlconfdata/net-vdpa-multiqueue.x86_64-latest.args
+++ b/tests/qemuxmlconfdata/net-vdpa-multiqueue.x86_64-latest.args
@@ -27,7 +27,7 @@ 
XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.config \
 -no-shutdown \
 -boot strict=on \
 -device 
'{"driver":"piix3-usb-uhci","id":"usb","bus":"pci.0","addr":"0x1.0x2"}' \
--add-fd set=0,fd=1732,opaque=net0-vdpa \
+-add-fd set=0,fd=XXXXXXX,opaque=net0-vdpa \
 -netdev 
'{"type":"vhost-vdpa","vhostdev":"/dev/fdset/0","queues":2,"id":"hostnet0"}' \
 -device 
'{"driver":"virtio-net-pci","mq":true,"vectors":6,"netdev":"hostnet0","id":"net0","mac":"52:54:00:95:db:c0","bus":"pci.0","addr":"0x2"}'
 \
 -audiodev '{"id":"audio1","driver":"none"}' \
diff --git a/tests/qemuxmlconfdata/net-vdpa.x86_64-latest.args 
b/tests/qemuxmlconfdata/net-vdpa.x86_64-latest.args
index 1fccd80199..118dd5dcb8 100644
--- a/tests/qemuxmlconfdata/net-vdpa.x86_64-latest.args
+++ b/tests/qemuxmlconfdata/net-vdpa.x86_64-latest.args
@@ -27,7 +27,7 @@ 
XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.config \
 -no-shutdown \
 -boot strict=on \
 -device 
'{"driver":"piix3-usb-uhci","id":"usb","bus":"pci.0","addr":"0x1.0x2"}' \
--add-fd set=0,fd=1732,opaque=net0-vdpa \
+-add-fd set=0,fd=XXXXXXX,opaque=net0-vdpa \
 -netdev '{"type":"vhost-vdpa","vhostdev":"/dev/fdset/0","id":"hostnet0"}' \
 -device 
'{"driver":"virtio-net-pci","netdev":"hostnet0","id":"net0","mac":"52:54:00:95:db:c0","bus":"pci.0","addr":"0x2"}'
 \
 -audiodev '{"id":"audio1","driver":"none"}' \
diff --git a/tests/qemuxmlconfdata/serial-file-chardev.x86_64-latest.args 
b/tests/qemuxmlconfdata/serial-file-chardev.x86_64-latest.args
index ca1867c247..59021c4443 100644
--- a/tests/qemuxmlconfdata/serial-file-chardev.x86_64-latest.args
+++ b/tests/qemuxmlconfdata/serial-file-chardev.x86_64-latest.args
@@ -29,7 +29,7 @@ 
XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.config \
 -device 
'{"driver":"piix3-usb-uhci","id":"usb","bus":"pci.0","addr":"0x1.0x2"}' \
 -blockdev 
'{"driver":"host_device","filename":"/dev/HostVG/QEMUGuest1","node-name":"libvirt-1-storage","read-only":false}'
 \
 -device 
'{"driver":"ide-hd","bus":"ide.0","unit":0,"drive":"libvirt-1-storage","id":"ide0-0-0","bootindex":1}'
 \
--add-fd set=0,fd=1750,opaque=serial0-source \
+-add-fd set=0,fd=XXXXXXX,opaque=serial0-source \
 -chardev file,id=charserial0,path=/dev/fdset/0,append=on \
 -device 
'{"driver":"isa-serial","chardev":"charserial0","id":"serial0","index":0}' \
 -audiodev '{"id":"audio1","driver":"none"}' \
diff --git a/tests/qemuxmlconfdata/serial-file-log.x86_64-latest.args 
b/tests/qemuxmlconfdata/serial-file-log.x86_64-latest.args
index 6cae9e89cd..260fb2f37a 100644
--- a/tests/qemuxmlconfdata/serial-file-log.x86_64-latest.args
+++ b/tests/qemuxmlconfdata/serial-file-log.x86_64-latest.args
@@ -29,8 +29,8 @@ 
XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.config \
 -device 
'{"driver":"piix3-usb-uhci","id":"usb","bus":"pci.0","addr":"0x1.0x2"}' \
 -blockdev 
'{"driver":"host_device","filename":"/dev/HostVG/QEMUGuest1","node-name":"libvirt-1-storage","read-only":false}'
 \
 -device 
'{"driver":"ide-hd","bus":"ide.0","unit":0,"drive":"libvirt-1-storage","id":"ide0-0-0","bootindex":1}'
 \
--add-fd set=0,fd=1750,opaque=serial0-source \
--add-fd set=1,fd=1751,opaque=serial0-log \
+-add-fd set=0,fd=XXXXXXX,opaque=serial0-source \
+-add-fd set=1,fd=XXXXXXX,opaque=serial0-log \
 -chardev 
file,id=charserial0,path=/dev/fdset/0,append=on,logfile=/dev/fdset/1,logappend=on
 \
 -device 
'{"driver":"isa-serial","chardev":"charserial0","id":"serial0","index":0}' \
 -audiodev '{"id":"audio1","driver":"none"}' \
diff --git a/tests/qemuxmlconfdata/serial-many-chardev.x86_64-latest.args 
b/tests/qemuxmlconfdata/serial-many-chardev.x86_64-latest.args
index 38d0033c9f..2841bbd3ba 100644
--- a/tests/qemuxmlconfdata/serial-many-chardev.x86_64-latest.args
+++ b/tests/qemuxmlconfdata/serial-many-chardev.x86_64-latest.args
@@ -31,7 +31,7 @@ 
XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.config \
 -device 
'{"driver":"ide-hd","bus":"ide.0","unit":0,"drive":"libvirt-1-storage","id":"ide0-0-0","bootindex":1}'
 \
 -chardev pty,id=charserial0 \
 -device 
'{"driver":"isa-serial","chardev":"charserial0","id":"serial0","index":0}' \
--add-fd set=0,fd=1750,opaque=serial1-source \
+-add-fd set=0,fd=XXXXXXX,opaque=serial1-source \
 -chardev file,id=charserial1,path=/dev/fdset/0,append=on \
 -device 
'{"driver":"isa-serial","chardev":"charserial1","id":"serial1","index":1}' \
 -audiodev '{"id":"audio1","driver":"none"}' \
diff --git a/tests/qemuxmlconfdata/tpm-passthrough-crb.x86_64-latest.args 
b/tests/qemuxmlconfdata/tpm-passthrough-crb.x86_64-latest.args
index cd210b50a0..319bf9579c 100644
--- a/tests/qemuxmlconfdata/tpm-passthrough-crb.x86_64-latest.args
+++ b/tests/qemuxmlconfdata/tpm-passthrough-crb.x86_64-latest.args
@@ -27,8 +27,8 @@ 
XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-TPM-VM/.config \
 -no-shutdown \
 -boot menu=on,strict=on \
 -device 
'{"driver":"piix3-usb-uhci","id":"usb","bus":"pci.0","addr":"0x1.0x2"}' \
--add-fd set=0,fd=1730,opaque=tpm0-tpm \
--add-fd set=1,fd=1731,opaque=tpm0-cancel \
+-add-fd set=0,fd=XXXXXXX,opaque=tpm0-tpm \
+-add-fd set=1,fd=XXXXXXX,opaque=tpm0-cancel \
 -tpmdev passthrough,id=tpm-tpm0,path=/dev/fdset/0,cancel-path=/dev/fdset/1 \
 -device '{"driver":"tpm-crb","tpmdev":"tpm-tpm0","id":"tpm0"}' \
 -audiodev '{"id":"audio1","driver":"none"}' \
diff --git a/tests/qemuxmlconfdata/tpm-passthrough.x86_64-latest.args 
b/tests/qemuxmlconfdata/tpm-passthrough.x86_64-latest.args
index cab016b666..896b6c3040 100644
--- a/tests/qemuxmlconfdata/tpm-passthrough.x86_64-latest.args
+++ b/tests/qemuxmlconfdata/tpm-passthrough.x86_64-latest.args
@@ -27,8 +27,8 @@ 
XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-TPM-VM/.config \
 -no-shutdown \
 -boot menu=on,strict=on \
 -device 
'{"driver":"piix3-usb-uhci","id":"usb","bus":"pci.0","addr":"0x1.0x2"}' \
--add-fd set=0,fd=1730,opaque=tpm0-tpm \
--add-fd set=1,fd=1731,opaque=tpm0-cancel \
+-add-fd set=0,fd=XXXXXXX,opaque=tpm0-tpm \
+-add-fd set=1,fd=XXXXXXX,opaque=tpm0-cancel \
 -tpmdev passthrough,id=tpm-tpm0,path=/dev/fdset/0,cancel-path=/dev/fdset/1 \
 -device '{"driver":"tpm-tis","tpmdev":"tpm-tpm0","id":"tpm0"}' \
 -audiodev '{"id":"audio1","driver":"none"}' \
diff --git a/tests/qemuxmlconftest.c b/tests/qemuxmlconftest.c
index ab62748013..6f5852657c 100644
--- a/tests/qemuxmlconftest.c
+++ b/tests/qemuxmlconftest.c
@@ -40,6 +40,10 @@

 static virQEMUDriver driver;

+/* this test case uses virTestDummyFDContextNew so we want to mock dup() to
+ * track FD hints properly */
+#include "virmock.h"
+VIR_TEST_MAKE_DUMMY_FD_INSTALL_DUP_MOCK

 static void
 testQemuPrepareHostdevPCI(virDomainHostdevDef *hostdev)
@@ -344,6 +348,191 @@ testCompareXMLToArgvValidateSchema(virCommand *cmd,
 }


+struct testCompareXMLToArgvStabilizeOneFindJSONObjectIterData {
+    const char *field;
+    bool recurse;
+    virJSONValue *ret;
+};
+
+static int
+testCompareXMLToArgvStabilizeOneFindJSONObjectIter(const char *key,
+                                                   virJSONValue *value,
+                                                   void *opaque)
+{
+    struct testCompareXMLToArgvStabilizeOneFindJSONObjectIterData *data = 
opaque;
+
+    /* negative value breaks iteration and returns specific return value */
+    if (STREQ(data->field, key))
+        return -1;
+
+    if (!data->recurse)
+        return 0;
+
+    if (!virJSONValueIsObject(value))
+        return 0;
+
+    if (virJSONValueObjectForeachKeyValue(value,
+                                          
testCompareXMLToArgvStabilizeOneFindJSONObjectIter,
+                                          data) == -2) {
+        /* -2 means that the callback found something; now if it was the above
+         * call that found the key we need to fill the pointer to what we've
+         * called it with */
+        if (data->ret == NULL)
+            data->ret = value;
+
+        return -1;
+    }
+
+    return 0;
+}
+
+
+/**
+ * testCompareXMLToArgvStabilizeOne:
+ * @arg: argument to modify (may be replaced by other memory)
+ * @field: field to replace
+ * @substitutions: optional hash-table to look up value of @field and replace
+ *                 it with the stored string
+ *
+ * Takes one qemu argument @arg and replaces the value of '@field' by a stable
+ * string, either 'XXXXXXX' if @substitutions is NULL or the value of @field
+ * wasn't found in @substitutions, or with the string from @substitutions if
+ * found.
+ *
+ * Works both on JSON and normal arguments.
+ */
+static void
+testCompareXMLToArgvStabilizeOne(char **arg,
+                                 const char *field,
+                                 GHashTable *substitutions,
+                                 bool recurseJSON)
+{
+    g_autofree char *oldarg = g_steal_pointer(arg);
+
+    if (*oldarg == '{') {
+        g_autoptr(virJSONValue) j = virJSONValueFromString(oldarg);
+        struct testCompareXMLToArgvStabilizeOneFindJSONObjectIterData data = {
+            .field = field,
+            .recurse = recurseJSON,
+        };
+        const char *curstr = NULL;
+
+        /* Any JSON args will be validated so this ought not to happen */
+        if (!j) {
+            *arg = g_steal_pointer(&oldarg);
+            return;
+        }
+
+        if (virJSONValueObjectForeachKeyValue(j,
+                                              
testCompareXMLToArgvStabilizeOneFindJSONObjectIter,
+                                              &data) == -2) {
+            /* -2 means that the callback found something; now if it was the 
above
+             * call that found the key we need to fill the pointer to what 
we've
+             * called it with */
+            if (data.ret == NULL)
+                data.ret = j;
+        }
+
+        if (data.ret) {
+            virJSONValue *cur = virJSONValueObjectGet(data.ret, field);
+
+            if (cur) {
+                switch (virJSONValueGetType(cur)) {
+                case VIR_JSON_TYPE_STRING:
+                    curstr = virJSONValueGetString(cur);
+                    break;
+
+                case VIR_JSON_TYPE_NUMBER:
+                    curstr = virJSONValueGetNumberString(cur);
+                    break;
+
+                case VIR_JSON_TYPE_OBJECT:
+                case VIR_JSON_TYPE_ARRAY:
+                case VIR_JSON_TYPE_BOOLEAN:
+                case VIR_JSON_TYPE_NULL:
+                    break;
+                }
+            }
+        }
+
+        if (curstr) {
+            g_autoptr(virJSONValue) newval = NULL;
+            const char *subst = NULL;
+
+            if (substitutions)
+                subst = g_hash_table_lookup(substitutions, curstr);
+
+            if (!subst)
+                subst = "XXXXXXX";
+
+            newval = virJSONValueNewString(g_strdup(subst));
+
+            ignore_value(virJSONValueObjectReplaceKey(data.ret, field, 
&newval));
+
+            *arg = virJSONValueToString(j, false);
+            return;
+        } else {
+            *arg = g_steal_pointer(&oldarg);
+            return;
+        }
+    } else {
+        g_autofree char *fieldmatch = g_strdup_printf("%s=", field);
+        char *match;
+        char *val;
+        char *rest;
+        const char *subst = NULL;
+
+        if (!(match = strstr(oldarg, fieldmatch))) {
+            *arg = g_steal_pointer(&oldarg);
+            return;
+        }
+
+        if ((rest = strchr(match, ',')))
+            *rest = '\0';
+
+        *match = '\0';
+
+        val = match + strlen(fieldmatch);
+
+        if (substitutions)
+            subst = g_hash_table_lookup(substitutions, val);
+
+        if (!subst)
+            subst = "XXXXXXX";
+
+        if (rest)
+            *rest = ',';
+
+        *arg = g_strdup_printf("%s%s%s%s", oldarg, fieldmatch, subst, 
NULLSTR_EMPTY(rest));
+    }
+}
+
+
+static void
+testCompareXMLToArgvStabilizeArgs(virCommand *cmd,
+                                  GHashTable *fdsubsts)
+{
+    char **args;
+    size_t nargs;
+    size_t a;
+
+    virCommandArgListAccess(cmd, &args, &nargs);
+
+    for (a = 0; a < nargs; a++) {
+        /* Any following replacements want also an argument for an option so
+         * so we guarantee that there's at least one extra arg */
+        if (a + 1 >= nargs)
+            break;
+
+        if (STREQ(args[a], "-add-fd")) {
+            testCompareXMLToArgvStabilizeOne(&args[a + 1], "fd", fdsubsts, 
false);
+
+            a++;
+        }
+    }
+}
+
+
 static int
 testInfoCheckDuplicate(testQemuInfo *info)
 {
@@ -724,6 +913,8 @@ testCompareXMLToArgv(const void *data)
     if (testCompareXMLToArgvValidateSchema(cmd, info) < 0)
         goto cleanup;

+    testCompareXMLToArgvStabilizeArgs(cmd, info->fdsubsts);
+
     if (virCommandToStringBuf(cmd, &actualBuf, true, false) < 0)
         goto cleanup;

@@ -801,10 +992,12 @@ testRun(const char *name,
     g_autofree char *name_argv = g_strdup_printf("QEMU XML def -> ARGV %s%s", 
name, suffix);
     g_autoptr(testQemuInfo) info = g_new0(testQemuInfo, 1);
     va_list ap;
+    g_autoptr(virTestDummyFDContext) fdsubsts = virTestDummyFDContextNew();

     info->name = name;
     info->suffix = suffix;
     info->conf = testConf;
+    info->fdsubsts = fdsubsts;

     va_start(ap, testConf);
     testQemuInfoSetArgs(info, ap);
diff --git a/tests/testutilsqemu.h b/tests/testutilsqemu.h
index dbc8e2dbdf..a39f03518b 100644
--- a/tests/testutilsqemu.h
+++ b/tests/testutilsqemu.h
@@ -120,6 +120,8 @@ struct _testQemuInfo {

     struct testQemuArgs args;
     struct testQemuConf *conf;
+
+    GHashTable *fdsubsts;
 };

 typedef struct _testQemuInfo testQemuInfo;
-- 
2.54.0

Reply via email to