aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/Makefile.include8
-rw-r--r--tests/crypto-tls-psk-helpers.c50
-rw-r--r--tests/crypto-tls-psk-helpers.h29
-rw-r--r--tests/qapi-schema/bad-if-empty-list.err1
-rw-r--r--tests/qapi-schema/bad-if-empty-list.exit1
-rw-r--r--tests/qapi-schema/bad-if-empty-list.json3
-rw-r--r--tests/qapi-schema/bad-if-empty-list.out0
-rw-r--r--tests/qapi-schema/bad-if-empty.err1
-rw-r--r--tests/qapi-schema/bad-if-empty.exit1
-rw-r--r--tests/qapi-schema/bad-if-empty.json3
-rw-r--r--tests/qapi-schema/bad-if-empty.out0
-rw-r--r--tests/qapi-schema/bad-if-list.err1
-rw-r--r--tests/qapi-schema/bad-if-list.exit1
-rw-r--r--tests/qapi-schema/bad-if-list.json3
-rw-r--r--tests/qapi-schema/bad-if-list.out0
-rw-r--r--tests/qapi-schema/bad-if.err1
-rw-r--r--tests/qapi-schema/bad-if.exit1
-rw-r--r--tests/qapi-schema/bad-if.json3
-rw-r--r--tests/qapi-schema/bad-if.out0
-rw-r--r--tests/qapi-schema/doc-good.json2
-rw-r--r--tests/qapi-schema/doc-good.out1
-rw-r--r--tests/qapi-schema/doc-good.texi2
-rw-r--r--tests/qapi-schema/qapi-schema-test.json26
-rw-r--r--tests/qapi-schema/qapi-schema-test.out35
-rw-r--r--tests/qapi-schema/test-qapi.py20
-rw-r--r--tests/qemu-iotests/222155
-rw-r--r--tests/qemu-iotests/222.out67
-rwxr-xr-xtests/qemu-iotests/223138
-rw-r--r--tests/qemu-iotests/223.out49
-rw-r--r--tests/qemu-iotests/group2
-rw-r--r--tests/test-crypto-tlssession.c179
-rw-r--r--tests/test-qga.c54
-rw-r--r--tests/test-qmp-cmds.c12
33 files changed, 822 insertions, 27 deletions
diff --git a/tests/Makefile.include b/tests/Makefile.include
index e8bb2d8f66..1affc49ca3 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -442,6 +442,10 @@ qapi-schema += args-unknown.json
qapi-schema += bad-base.json
qapi-schema += bad-data.json
qapi-schema += bad-ident.json
+qapi-schema += bad-if.json
+qapi-schema += bad-if-empty.json
+qapi-schema += bad-if-empty-list.json
+qapi-schema += bad-if-list.json
qapi-schema += bad-type-bool.json
qapi-schema += bad-type-dict.json
qapi-schema += bad-type-int.json
@@ -723,7 +727,9 @@ tests/test-crypto-tlscredsx509$(EXESUF): tests/test-crypto-tlscredsx509.o \
tests/test-crypto-tlssession.o-cflags := $(TASN1_CFLAGS)
tests/test-crypto-tlssession$(EXESUF): tests/test-crypto-tlssession.o \
- tests/crypto-tls-x509-helpers.o tests/pkix_asn1_tab.o $(test-crypto-obj-y)
+ tests/crypto-tls-x509-helpers.o tests/pkix_asn1_tab.o \
+ tests/crypto-tls-psk-helpers.o \
+ $(test-crypto-obj-y)
tests/test-util-sockets$(EXESUF): tests/test-util-sockets.o \
tests/socket-helpers.o $(test-util-obj-y)
tests/test-io-task$(EXESUF): tests/test-io-task.o $(test-io-obj-y)
diff --git a/tests/crypto-tls-psk-helpers.c b/tests/crypto-tls-psk-helpers.c
new file mode 100644
index 0000000000..a8395477c3
--- /dev/null
+++ b/tests/crypto-tls-psk-helpers.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2015-2018 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard W.M. Jones <rjones@redhat.com>
+ */
+
+#include "qemu/osdep.h"
+
+/* Include this first because it defines QCRYPTO_HAVE_TLS_TEST_SUPPORT */
+#include "crypto-tls-x509-helpers.h"
+
+#include "crypto-tls-psk-helpers.h"
+#include "qemu/sockets.h"
+
+#ifdef QCRYPTO_HAVE_TLS_TEST_SUPPORT
+
+void test_tls_psk_init(const char *pskfile)
+{
+ FILE *fp;
+
+ fp = fopen(pskfile, "w");
+ if (fp == NULL) {
+ g_critical("Failed to create pskfile %s", pskfile);
+ abort();
+ }
+ /* Don't do this in real applications! Use psktool. */
+ fprintf(fp, "qemu:009d5638c40fde0c\n");
+ fclose(fp);
+}
+
+void test_tls_psk_cleanup(const char *pskfile)
+{
+ unlink(pskfile);
+}
+
+#endif /* QCRYPTO_HAVE_TLS_TEST_SUPPORT */
diff --git a/tests/crypto-tls-psk-helpers.h b/tests/crypto-tls-psk-helpers.h
new file mode 100644
index 0000000000..9aec29f1a0
--- /dev/null
+++ b/tests/crypto-tls-psk-helpers.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2015-2018 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Author: Richard W.M. Jones <rjones@redhat.com>
+ */
+
+#include <gnutls/gnutls.h>
+
+#ifdef QCRYPTO_HAVE_TLS_TEST_SUPPORT
+# include "qemu-common.h"
+
+void test_tls_psk_init(const char *keyfile);
+void test_tls_psk_cleanup(const char *keyfile);
+
+#endif /* QCRYPTO_HAVE_TLS_TEST_SUPPORT */
diff --git a/tests/qapi-schema/bad-if-empty-list.err b/tests/qapi-schema/bad-if-empty-list.err
new file mode 100644
index 0000000000..75fe6497bc
--- /dev/null
+++ b/tests/qapi-schema/bad-if-empty-list.err
@@ -0,0 +1 @@
+tests/qapi-schema/bad-if-empty-list.json:2: 'if' condition [] is useless
diff --git a/tests/qapi-schema/bad-if-empty-list.exit b/tests/qapi-schema/bad-if-empty-list.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/bad-if-empty-list.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/bad-if-empty-list.json b/tests/qapi-schema/bad-if-empty-list.json
new file mode 100644
index 0000000000..94f2eb8670
--- /dev/null
+++ b/tests/qapi-schema/bad-if-empty-list.json
@@ -0,0 +1,3 @@
+# check empty 'if' list
+{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
+ 'if': [] }
diff --git a/tests/qapi-schema/bad-if-empty-list.out b/tests/qapi-schema/bad-if-empty-list.out
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/qapi-schema/bad-if-empty-list.out
diff --git a/tests/qapi-schema/bad-if-empty.err b/tests/qapi-schema/bad-if-empty.err
new file mode 100644
index 0000000000..358bdc3e51
--- /dev/null
+++ b/tests/qapi-schema/bad-if-empty.err
@@ -0,0 +1 @@
+tests/qapi-schema/bad-if-empty.json:2: 'if' condition '' makes no sense
diff --git a/tests/qapi-schema/bad-if-empty.exit b/tests/qapi-schema/bad-if-empty.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/bad-if-empty.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/bad-if-empty.json b/tests/qapi-schema/bad-if-empty.json
new file mode 100644
index 0000000000..fe1dd4eca6
--- /dev/null
+++ b/tests/qapi-schema/bad-if-empty.json
@@ -0,0 +1,3 @@
+# check empty 'if'
+{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
+ 'if': '' }
diff --git a/tests/qapi-schema/bad-if-empty.out b/tests/qapi-schema/bad-if-empty.out
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/qapi-schema/bad-if-empty.out
diff --git a/tests/qapi-schema/bad-if-list.err b/tests/qapi-schema/bad-if-list.err
new file mode 100644
index 0000000000..0af6316f78
--- /dev/null
+++ b/tests/qapi-schema/bad-if-list.err
@@ -0,0 +1 @@
+tests/qapi-schema/bad-if-list.json:2: 'if' condition '' makes no sense
diff --git a/tests/qapi-schema/bad-if-list.exit b/tests/qapi-schema/bad-if-list.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/bad-if-list.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/bad-if-list.json b/tests/qapi-schema/bad-if-list.json
new file mode 100644
index 0000000000..49ced9b9ca
--- /dev/null
+++ b/tests/qapi-schema/bad-if-list.json
@@ -0,0 +1,3 @@
+# check invalid 'if' content
+{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
+ 'if': ['foo', ''] }
diff --git a/tests/qapi-schema/bad-if-list.out b/tests/qapi-schema/bad-if-list.out
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/qapi-schema/bad-if-list.out
diff --git a/tests/qapi-schema/bad-if.err b/tests/qapi-schema/bad-if.err
new file mode 100644
index 0000000000..c2e3f5f44c
--- /dev/null
+++ b/tests/qapi-schema/bad-if.err
@@ -0,0 +1 @@
+tests/qapi-schema/bad-if.json:2: 'if' condition must be a string or a list of strings
diff --git a/tests/qapi-schema/bad-if.exit b/tests/qapi-schema/bad-if.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/bad-if.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/bad-if.json b/tests/qapi-schema/bad-if.json
new file mode 100644
index 0000000000..3edd1a0bf2
--- /dev/null
+++ b/tests/qapi-schema/bad-if.json
@@ -0,0 +1,3 @@
+# check invalid 'if' type
+{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
+ 'if': { 'value': 'defined(TEST_IF_STRUCT)' } }
diff --git a/tests/qapi-schema/bad-if.out b/tests/qapi-schema/bad-if.out
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/qapi-schema/bad-if.out
diff --git a/tests/qapi-schema/doc-good.json b/tests/qapi-schema/doc-good.json
index 97ab4625ff..984cd8ed06 100644
--- a/tests/qapi-schema/doc-good.json
+++ b/tests/qapi-schema/doc-good.json
@@ -55,7 +55,7 @@
#
# @two is undocumented
##
-{ 'enum': 'Enum', 'data': [ 'one', 'two' ] }
+{ 'enum': 'Enum', 'data': [ 'one', 'two' ], 'if': 'defined(IFCOND)' }
##
# @Base:
diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.out
index 9c8a4838e1..35f3f1164c 100644
--- a/tests/qapi-schema/doc-good.out
+++ b/tests/qapi-schema/doc-good.out
@@ -3,6 +3,7 @@ enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
prefix QTYPE
module doc-good.json
enum Enum ['one', 'two']
+ if ['defined(IFCOND)']
object Base
member base1: Enum optional=False
object Variant1
diff --git a/tests/qapi-schema/doc-good.texi b/tests/qapi-schema/doc-good.texi
index 0aed2300a5..e42eace474 100644
--- a/tests/qapi-schema/doc-good.texi
+++ b/tests/qapi-schema/doc-good.texi
@@ -89,6 +89,8 @@ Not documented
@end table
@code{two} is undocumented
+
+@b{If:} @code{defined(IFCOND)}
@end deftp
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index e9e401c01f..11aa4c8f8d 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -56,6 +56,9 @@
'data': { 'string0': 'str',
'dict1': 'UserDefTwoDict' } }
+{ 'struct': 'UserDefThree',
+ 'data': { 'string0': 'str' } }
+
# dummy struct to force generation of array types not otherwise mentioned
{ 'struct': 'ForceArrays',
'data': { 'unused1':['UserDefOne'], 'unused2':['UserDefTwo'],
@@ -193,3 +196,26 @@
'data': { 'a': ['__org.qemu_x-Enum'], 'b': ['__org.qemu_x-Struct'],
'c': '__org.qemu_x-Union2', 'd': '__org.qemu_x-Alt' },
'returns': '__org.qemu_x-Union1' }
+
+# test 'if' condition handling
+
+{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
+ 'if': 'defined(TEST_IF_STRUCT)' }
+
+{ 'enum': 'TestIfEnum', 'data': [ 'foo', 'bar' ],
+ 'if': 'defined(TEST_IF_ENUM)' }
+
+{ 'union': 'TestIfUnion', 'data': { 'foo': 'TestStruct' },
+ 'if': 'defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)' }
+
+{ 'alternate': 'TestIfAlternate', 'data': { 'foo': 'int', 'bar': 'TestStruct' },
+ 'if': 'defined(TEST_IF_ALT) && defined(TEST_IF_STRUCT)' }
+
+{ 'command': 'TestIfCmd', 'data': { 'foo': 'TestIfStruct' },
+ 'returns': 'UserDefThree',
+ 'if': ['defined(TEST_IF_CMD)', 'defined(TEST_IF_STRUCT)'] }
+
+{ 'command': 'TestCmdReturnDefThree', 'returns': 'UserDefThree' }
+
+{ 'event': 'TestIfEvent', 'data': { 'foo': 'TestIfStruct' },
+ 'if': 'defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)' }
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index 0dbcdafa3c..0da92455da 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -36,6 +36,8 @@ object UserDefTwoDict
object UserDefTwo
member string0: str optional=False
member dict1: UserDefTwoDict optional=False
+object UserDefThree
+ member string0: str optional=False
object ForceArrays
member unused1: UserDefOneList optional=False
member unused2: UserDefTwoList optional=False
@@ -233,3 +235,36 @@ object q_obj___org.qemu_x-command-arg
member d: __org.qemu_x-Alt optional=False
command __org.qemu_x-command q_obj___org.qemu_x-command-arg -> __org.qemu_x-Union1
gen=True success_response=True boxed=False oob=False preconfig=False
+object TestIfStruct
+ member foo: int optional=False
+ if ['defined(TEST_IF_STRUCT)']
+enum TestIfEnum ['foo', 'bar']
+ if ['defined(TEST_IF_ENUM)']
+object q_obj_TestStruct-wrapper
+ member data: TestStruct optional=False
+enum TestIfUnionKind ['foo']
+ if ['defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)']
+object TestIfUnion
+ member type: TestIfUnionKind optional=False
+ tag type
+ case foo: q_obj_TestStruct-wrapper
+ if ['defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)']
+alternate TestIfAlternate
+ tag type
+ case foo: int
+ case bar: TestStruct
+ if ['defined(TEST_IF_ALT) && defined(TEST_IF_STRUCT)']
+object q_obj_TestIfCmd-arg
+ member foo: TestIfStruct optional=False
+ if ['defined(TEST_IF_CMD)', 'defined(TEST_IF_STRUCT)']
+command TestIfCmd q_obj_TestIfCmd-arg -> UserDefThree
+ gen=True success_response=True boxed=False oob=False preconfig=False
+ if ['defined(TEST_IF_CMD)', 'defined(TEST_IF_STRUCT)']
+command TestCmdReturnDefThree None -> UserDefThree
+ gen=True success_response=True boxed=False oob=False preconfig=False
+object q_obj_TestIfEvent-arg
+ member foo: TestIfStruct optional=False
+ if ['defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)']
+event TestIfEvent q_obj_TestIfEvent-arg
+ boxed=False
+ if ['defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)']
diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
index 4512a41504..f514fe71e4 100644
--- a/tests/qapi-schema/test-qapi.py
+++ b/tests/qapi-schema/test-qapi.py
@@ -23,12 +23,13 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
def visit_include(self, name, info):
print('include %s' % name)
- def visit_enum_type(self, name, info, values, prefix):
+ def visit_enum_type(self, name, info, ifcond, values, prefix):
print('enum %s %s' % (name, values))
if prefix:
print(' prefix %s' % prefix)
+ self._print_if(ifcond)
- def visit_object_type(self, name, info, base, members, variants):
+ def visit_object_type(self, name, info, ifcond, base, members, variants):
print('object %s' % name)
if base:
print(' base %s' % base.name)
@@ -36,21 +37,25 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
print(' member %s: %s optional=%s' % \
(m.name, m.type.name, m.optional))
self._print_variants(variants)
+ self._print_if(ifcond)
- def visit_alternate_type(self, name, info, variants):
+ def visit_alternate_type(self, name, info, ifcond, variants):
print('alternate %s' % name)
self._print_variants(variants)
+ self._print_if(ifcond)
- def visit_command(self, name, info, arg_type, ret_type, gen,
+ def visit_command(self, name, info, ifcond, arg_type, ret_type, gen,
success_response, boxed, allow_oob, allow_preconfig):
print('command %s %s -> %s' % \
(name, arg_type and arg_type.name, ret_type and ret_type.name))
print(' gen=%s success_response=%s boxed=%s oob=%s preconfig=%s' % \
(gen, success_response, boxed, allow_oob, allow_preconfig))
+ self._print_if(ifcond)
- def visit_event(self, name, info, arg_type, boxed):
+ def visit_event(self, name, info, ifcond, arg_type, boxed):
print('event %s %s' % (name, arg_type and arg_type.name))
print(' boxed=%s' % boxed)
+ self._print_if(ifcond)
@staticmethod
def _print_variants(variants):
@@ -59,6 +64,11 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
for v in variants.variants:
print(' case %s: %s' % (v.name, v.type.name))
+ @staticmethod
+ def _print_if(ifcond, indent=4):
+ if ifcond:
+ print('%sif %s' % (' ' * indent, ifcond))
+
try:
schema = QAPISchema(sys.argv[1])
diff --git a/tests/qemu-iotests/222 b/tests/qemu-iotests/222
new file mode 100644
index 0000000000..ff3bfc1470
--- /dev/null
+++ b/tests/qemu-iotests/222
@@ -0,0 +1,155 @@
+#!/usr/bin/env python
+#
+# This test covers the basic fleecing workflow, which provides a
+# point-in-time snapshot of a node that can be queried over NBD.
+#
+# Copyright (C) 2018 Red Hat, Inc.
+# John helped, too.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# Creator/Owner: John Snow <jsnow@redhat.com>
+
+import iotests
+from iotests import log, qemu_img, qemu_io, qemu_io_silent
+
+iotests.verify_platform(['linux'])
+
+patterns = [("0x5d", "0", "64k"),
+ ("0xd5", "1M", "64k"),
+ ("0xdc", "32M", "64k"),
+ ("0xcd", "0x3ff0000", "64k")] # 64M - 64K
+
+overwrite = [("0xab", "0", "64k"), # Full overwrite
+ ("0xad", "0x00f8000", "64k"), # Partial-left (1M-32K)
+ ("0x1d", "0x2008000", "64k"), # Partial-right (32M+32K)
+ ("0xea", "0x3fe0000", "64k")] # Adjacent-left (64M - 128K)
+
+zeroes = [("0", "0x00f8000", "32k"), # Left-end of partial-left (1M-32K)
+ ("0", "0x2010000", "32k"), # Right-end of partial-right (32M+64K)
+ ("0", "0x3fe0000", "64k")] # overwrite[3]
+
+remainder = [("0xd5", "0x108000", "32k"), # Right-end of partial-left [1]
+ ("0xdc", "32M", "32k"), # Left-end of partial-right [2]
+ ("0xcd", "0x3ff0000", "64k")] # patterns[3]
+
+with iotests.FilePath('base.img') as base_img_path, \
+ iotests.FilePath('fleece.img') as fleece_img_path, \
+ iotests.FilePath('nbd.sock') as nbd_sock_path, \
+ iotests.VM() as vm:
+
+ log('--- Setting up images ---')
+ log('')
+
+ assert qemu_img('create', '-f', iotests.imgfmt, base_img_path, '64M') == 0
+ assert qemu_img('create', '-f', "qcow2", fleece_img_path, '64M') == 0
+
+ for p in patterns:
+ qemu_io('-f', iotests.imgfmt,
+ '-c', 'write -P%s %s %s' % p, base_img_path)
+
+ log('Done')
+
+ log('')
+ log('--- Launching VM ---')
+ log('')
+
+ vm.add_drive(base_img_path)
+ vm.launch()
+ log('Done')
+
+ log('')
+ log('--- Setting up Fleecing Graph ---')
+ log('')
+
+ src_node = "drive0"
+ tgt_node = "fleeceNode"
+
+ # create tgt_node backed by src_node
+ log(vm.qmp("blockdev-add", **{
+ "driver": "qcow2",
+ "node-name": tgt_node,
+ "file": {
+ "driver": "file",
+ "filename": fleece_img_path,
+ },
+ "backing": src_node,
+ }))
+
+ # Establish COW from source to fleecing node
+ log(vm.qmp("blockdev-backup",
+ device=src_node,
+ target=tgt_node,
+ sync="none"))
+
+ log('')
+ log('--- Setting up NBD Export ---')
+ log('')
+
+ nbd_uri = 'nbd+unix:///%s?socket=%s' % (tgt_node, nbd_sock_path)
+ log(vm.qmp("nbd-server-start",
+ **{"addr": { "type": "unix",
+ "data": { "path": nbd_sock_path } } }))
+
+ log(vm.qmp("nbd-server-add", device=tgt_node))
+
+ log('')
+ log('--- Sanity Check ---')
+ log('')
+
+ for p in (patterns + zeroes):
+ cmd = "read -P%s %s %s" % p
+ log(cmd)
+ assert qemu_io_silent('-r', '-f', 'raw', '-c', cmd, nbd_uri) == 0
+
+ log('')
+ log('--- Testing COW ---')
+ log('')
+
+ for p in overwrite:
+ cmd = "write -P%s %s %s" % p
+ log(cmd)
+ log(vm.hmp_qemu_io(src_node, cmd))
+
+ log('')
+ log('--- Verifying Data ---')
+ log('')
+
+ for p in (patterns + zeroes):
+ cmd = "read -P%s %s %s" % p
+ log(cmd)
+ assert qemu_io_silent('-r', '-f', 'raw', '-c', cmd, nbd_uri) == 0
+
+ log('')
+ log('--- Cleanup ---')
+ log('')
+
+ log(vm.qmp('block-job-cancel', device=src_node))
+ log(vm.event_wait('BLOCK_JOB_CANCELLED'),
+ filters=[iotests.filter_qmp_event])
+ log(vm.qmp('nbd-server-stop'))
+ log(vm.qmp('blockdev-del', node_name=tgt_node))
+ vm.shutdown()
+
+ log('')
+ log('--- Confirming writes ---')
+ log('')
+
+ for p in (overwrite + remainder):
+ cmd = "read -P%s %s %s" % p
+ log(cmd)
+ assert qemu_io_silent(base_img_path, '-c', cmd) == 0
+
+ log('')
+ log('Done')
diff --git a/tests/qemu-iotests/222.out b/tests/qemu-iotests/222.out
new file mode 100644
index 0000000000..48f336a02b
--- /dev/null
+++ b/tests/qemu-iotests/222.out
@@ -0,0 +1,67 @@
+--- Setting up images ---
+
+Done
+
+--- Launching VM ---
+
+Done
+
+--- Setting up Fleecing Graph ---
+
+{u'return': {}}
+{u'return': {}}
+
+--- Setting up NBD Export ---
+
+{u'return': {}}
+{u'return': {}}
+
+--- Sanity Check ---
+
+read -P0x5d 0 64k
+read -P0xd5 1M 64k
+read -P0xdc 32M 64k
+read -P0xcd 0x3ff0000 64k
+read -P0 0x00f8000 32k
+read -P0 0x2010000 32k
+read -P0 0x3fe0000 64k
+
+--- Testing COW ---
+
+write -P0xab 0 64k
+{u'return': u''}
+write -P0xad 0x00f8000 64k
+{u'return': u''}
+write -P0x1d 0x2008000 64k
+{u'return': u''}
+write -P0xea 0x3fe0000 64k
+{u'return': u''}
+
+--- Verifying Data ---
+
+read -P0x5d 0 64k
+read -P0xd5 1M 64k
+read -P0xdc 32M 64k
+read -P0xcd 0x3ff0000 64k
+read -P0 0x00f8000 32k
+read -P0 0x2010000 32k
+read -P0 0x3fe0000 64k
+
+--- Cleanup ---
+
+{u'return': {}}
+{u'timestamp': {u'seconds': 'SECS', u'microseconds': 'USECS'}, u'data': {u'device': u'drive0', u'type': u'backup', u'speed': 0, u'len': 67108864, u'offset': 393216}, u'event': u'BLOCK_JOB_CANCELLED'}
+{u'return': {}}
+{u'return': {}}
+
+--- Confirming writes ---
+
+read -P0xab 0 64k
+read -P0xad 0x00f8000 64k
+read -P0x1d 0x2008000 64k
+read -P0xea 0x3fe0000 64k
+read -P0xd5 0x108000 32k
+read -P0xdc 32M 32k
+read -P0xcd 0x3ff0000 64k
+
+Done
diff --git a/tests/qemu-iotests/223 b/tests/qemu-iotests/223
new file mode 100755
index 0000000000..b63b7a4f9e
--- /dev/null
+++ b/tests/qemu-iotests/223
@@ -0,0 +1,138 @@
+#!/bin/bash
+#
+# Test reading dirty bitmap over NBD
+#
+# Copyright (C) 2018 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+seq="$(basename $0)"
+echo "QA output created by $seq"
+
+here="$PWD"
+status=1 # failure is the default!
+
+_cleanup()
+{
+ _cleanup_test_img
+ _cleanup_qemu
+ rm -f "$TEST_DIR/nbd"
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+. ./common.qemu
+
+_supported_fmt qcow2
+_supported_proto file # uses NBD as well
+_supported_os Linux
+
+function do_run_qemu()
+{
+ echo Testing: "$@"
+ $QEMU -nographic -qmp stdio -serial none "$@"
+ echo
+}
+
+function run_qemu()
+{
+ do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \
+ | _filter_qemu | _filter_imgfmt \
+ | _filter_actual_image_size
+}
+
+echo
+echo "=== Create partially sparse image, then add dirty bitmap ==="
+echo
+
+_make_test_img 4M
+$QEMU_IO -c 'w -P 0x11 1M 2M' "$TEST_IMG" | _filter_qemu_io
+run_qemu <<EOF
+{ "execute": "qmp_capabilities" }
+{ "execute": "blockdev-add",
+ "arguments": {
+ "driver": "$IMGFMT",
+ "node-name": "n",
+ "file": {
+ "driver": "file",
+ "filename": "$TEST_IMG"
+ }
+ }
+}
+{ "execute": "block-dirty-bitmap-add",
+ "arguments": {
+ "node": "n",
+ "name": "b",
+ "persistent": true
+ }
+}
+{ "execute": "quit" }
+EOF
+
+echo
+echo "=== Write part of the file under active bitmap ==="
+echo
+
+$QEMU_IO -c 'w -P 0x22 2M 2M' "$TEST_IMG" | _filter_qemu_io
+
+echo
+echo "=== End dirty bitmap, and start serving image over NBD ==="
+echo
+
+_launch_qemu 2> >(_filter_nbd)
+
+silent=
+_send_qemu_cmd $QEMU_HANDLE '{"execute":"qmp_capabilities"}' "return"
+_send_qemu_cmd $QEMU_HANDLE '{"execute":"blockdev-add",
+ "arguments":{"driver":"qcow2", "node-name":"n",
+ "file":{"driver":"file", "filename":"'"$TEST_IMG"'"}}}' "return"
+_send_qemu_cmd $QEMU_HANDLE '{"execute":"x-block-dirty-bitmap-disable",
+ "arguments":{"node":"n", "name":"b"}}' "return"
+_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-start",
+ "arguments":{"addr":{"type":"unix",
+ "data":{"path":"'"$TEST_DIR/nbd"'"}}}}' "return"
+_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add",
+ "arguments":{"device":"n"}}' "return"
+_send_qemu_cmd $QEMU_HANDLE '{"execute":"x-nbd-server-add-bitmap",
+ "arguments":{"name":"n", "bitmap":"b"}}' "return"
+
+echo
+echo "=== Contrast normal status with dirty-bitmap status ==="
+echo
+
+QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT
+IMG="driver=nbd,export=n,server.type=unix,server.path=$TEST_DIR/nbd"
+$QEMU_IO -r -c 'r -P 0 0 1m' -c 'r -P 0x11 1m 1m' \
+ -c 'r -P 0x22 2m 2m' --image-opts "$IMG" | _filter_qemu_io
+$QEMU_IMG map --output=json --image-opts \
+ "$IMG" | _filter_qemu_img_map
+$QEMU_IMG map --output=json --image-opts \
+ "$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b" | _filter_qemu_img_map
+
+echo
+echo "=== End NBD server ==="
+echo
+
+_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-remove",
+ "arguments":{"name":"n"}}' "return"
+_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-stop"}' "return"
+_send_qemu_cmd $QEMU_HANDLE '{"execute":"quit"}' "return"
+
+# success, all done
+echo '*** done'
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/223.out b/tests/qemu-iotests/223.out
new file mode 100644
index 0000000000..33021c8e6a
--- /dev/null
+++ b/tests/qemu-iotests/223.out
@@ -0,0 +1,49 @@
+QA output created by 223
+
+=== Create partially sparse image, then add dirty bitmap ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4194304
+wrote 2097152/2097152 bytes at offset 1048576
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Testing:
+QMP_VERSION
+{"return": {}}
+{"return": {}}
+{"return": {}}
+{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+
+
+=== Write part of the file under active bitmap ===
+
+wrote 2097152/2097152 bytes at offset 2097152
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+=== End dirty bitmap, and start serving image over NBD ===
+
+{"return": {}}
+{"return": {}}
+{"return": {}}
+{"return": {}}
+{"return": {}}
+{"return": {}}
+
+=== Contrast normal status with dirty-bitmap status ===
+
+read 1048576/1048576 bytes at offset 0
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 1048576/1048576 bytes at offset 1048576
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 2097152/2097152 bytes at offset 2097152
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+[{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": false},
+{ "start": 1048576, "length": 3145728, "depth": 0, "zero": false, "data": true}]
+[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true},
+{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": false}]
+
+=== End NBD server ===
+
+{"return": {}}
+{"return": {}}
+{"return": {}}
+*** done
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index eea75819d2..af309ebba7 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -220,3 +220,5 @@
218 rw auto quick
219 rw auto
221 rw auto quick
+222 rw auto quick
+223 rw auto quick
diff --git a/tests/test-crypto-tlssession.c b/tests/test-crypto-tlssession.c
index 82f21c27f2..7bd811796e 100644
--- a/tests/test-crypto-tlssession.c
+++ b/tests/test-crypto-tlssession.c
@@ -21,7 +21,9 @@
#include "qemu/osdep.h"
#include "crypto-tls-x509-helpers.h"
+#include "crypto-tls-psk-helpers.h"
#include "crypto/tlscredsx509.h"
+#include "crypto/tlscredspsk.h"
#include "crypto/tlssession.h"
#include "qom/object_interfaces.h"
#include "qapi/error.h"
@@ -31,20 +33,9 @@
#ifdef QCRYPTO_HAVE_TLS_TEST_SUPPORT
#define WORKDIR "tests/test-crypto-tlssession-work/"
+#define PSKFILE WORKDIR "keys.psk"
#define KEYFILE WORKDIR "key-ctx.pem"
-struct QCryptoTLSSessionTestData {
- const char *servercacrt;
- const char *clientcacrt;
- const char *servercrt;
- const char *clientcrt;
- bool expectServerFail;
- bool expectClientFail;
- const char *hostname;
- const char *const *wildcards;
-};
-
-
static ssize_t testWrite(const char *buf, size_t len, void *opaque)
{
int *fd = opaque;
@@ -59,9 +50,150 @@ static ssize_t testRead(char *buf, size_t len, void *opaque)
return read(*fd, buf, len);
}
-static QCryptoTLSCreds *test_tls_creds_create(QCryptoTLSCredsEndpoint endpoint,
- const char *certdir,
- Error **errp)
+static QCryptoTLSCreds *test_tls_creds_psk_create(
+ QCryptoTLSCredsEndpoint endpoint,
+ const char *dir,
+ Error **errp)
+{
+ Error *err = NULL;
+ Object *parent = object_get_objects_root();
+ Object *creds = object_new_with_props(
+ TYPE_QCRYPTO_TLS_CREDS_PSK,
+ parent,
+ (endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER ?
+ "testtlscredsserver" : "testtlscredsclient"),
+ &err,
+ "endpoint", (endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER ?
+ "server" : "client"),
+ "dir", dir,
+ "priority", "NORMAL",
+ NULL
+ );
+
+ if (err) {
+ error_propagate(errp, err);
+ return NULL;
+ }
+ return QCRYPTO_TLS_CREDS(creds);
+}
+
+
+static void test_crypto_tls_session_psk(void)
+{
+ QCryptoTLSCreds *clientCreds;
+ QCryptoTLSCreds *serverCreds;
+ QCryptoTLSSession *clientSess = NULL;
+ QCryptoTLSSession *serverSess = NULL;
+ int channel[2];
+ bool clientShake = false;
+ bool serverShake = false;
+ Error *err = NULL;
+ int ret;
+
+ /* We'll use this for our fake client-server connection */
+ ret = socketpair(AF_UNIX, SOCK_STREAM, 0, channel);
+ g_assert(ret == 0);
+
+ /*
+ * We have an evil loop to do the handshake in a single
+ * thread, so we need these non-blocking to avoid deadlock
+ * of ourselves
+ */
+ qemu_set_nonblock(channel[0]);
+ qemu_set_nonblock(channel[1]);
+
+ clientCreds = test_tls_creds_psk_create(
+ QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT,
+ WORKDIR,
+ &err);
+ g_assert(clientCreds != NULL);
+
+ serverCreds = test_tls_creds_psk_create(
+ QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
+ WORKDIR,
+ &err);
+ g_assert(serverCreds != NULL);
+
+ /* Now the real part of the test, setup the sessions */
+ clientSess = qcrypto_tls_session_new(
+ clientCreds, NULL, NULL,
+ QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT, &err);
+ serverSess = qcrypto_tls_session_new(
+ serverCreds, NULL, NULL,
+ QCRYPTO_TLS_CREDS_ENDPOINT_SERVER, &err);
+
+ g_assert(clientSess != NULL);
+ g_assert(serverSess != NULL);
+
+ /* For handshake to work, we need to set the I/O callbacks
+ * to read/write over the socketpair
+ */
+ qcrypto_tls_session_set_callbacks(serverSess,
+ testWrite, testRead,
+ &channel[0]);
+ qcrypto_tls_session_set_callbacks(clientSess,
+ testWrite, testRead,
+ &channel[1]);
+
+ /*
+ * Finally we loop around & around doing handshake on each
+ * session until we get an error, or the handshake completes.
+ * This relies on the socketpair being nonblocking to avoid
+ * deadlocking ourselves upon handshake
+ */
+ do {
+ int rv;
+ if (!serverShake) {
+ rv = qcrypto_tls_session_handshake(serverSess,
+ &err);
+ g_assert(rv >= 0);
+ if (qcrypto_tls_session_get_handshake_status(serverSess) ==
+ QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
+ serverShake = true;
+ }
+ }
+ if (!clientShake) {
+ rv = qcrypto_tls_session_handshake(clientSess,
+ &err);
+ g_assert(rv >= 0);
+ if (qcrypto_tls_session_get_handshake_status(clientSess) ==
+ QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
+ clientShake = true;
+ }
+ }
+ } while (!clientShake && !serverShake);
+
+
+ /* Finally make sure the server & client validation is successful. */
+ g_assert(qcrypto_tls_session_check_credentials(serverSess, &err) == 0);
+ g_assert(qcrypto_tls_session_check_credentials(clientSess, &err) == 0);
+
+ object_unparent(OBJECT(serverCreds));
+ object_unparent(OBJECT(clientCreds));
+
+ qcrypto_tls_session_free(serverSess);
+ qcrypto_tls_session_free(clientSess);
+
+ close(channel[0]);
+ close(channel[1]);
+}
+
+
+struct QCryptoTLSSessionTestData {
+ const char *servercacrt;
+ const char *clientcacrt;
+ const char *servercrt;
+ const char *clientcrt;
+ bool expectServerFail;
+ bool expectClientFail;
+ const char *hostname;
+ const char *const *wildcards;
+};
+
+static QCryptoTLSCreds *test_tls_creds_x509_create(
+ QCryptoTLSCredsEndpoint endpoint,
+ const char *certdir,
+ Error **errp)
{
Error *err = NULL;
Object *parent = object_get_objects_root();
@@ -104,7 +236,7 @@ static QCryptoTLSCreds *test_tls_creds_create(QCryptoTLSCredsEndpoint endpoint,
* initiate a TLS session across them. Finally do
* do actual cert validation tests
*/
-static void test_crypto_tls_session(const void *opaque)
+static void test_crypto_tls_session_x509(const void *opaque)
{
struct QCryptoTLSSessionTestData *data =
(struct QCryptoTLSSessionTestData *)opaque;
@@ -159,13 +291,13 @@ static void test_crypto_tls_session(const void *opaque)
g_assert(link(KEYFILE,
CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY) == 0);
- clientCreds = test_tls_creds_create(
+ clientCreds = test_tls_creds_x509_create(
QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT,
CLIENT_CERT_DIR,
&err);
g_assert(clientCreds != NULL);
- serverCreds = test_tls_creds_create(
+ serverCreds = test_tls_creds_x509_create(
QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
SERVER_CERT_DIR,
&err);
@@ -285,7 +417,13 @@ int main(int argc, char **argv)
mkdir(WORKDIR, 0700);
test_tls_init(KEYFILE);
+ test_tls_psk_init(PSKFILE);
+
+ /* Simple initial test using Pre-Shared Keys. */
+ g_test_add_func("/qcrypto/tlssession/psk",
+ test_crypto_tls_session_psk);
+ /* More complex tests using X.509 certificates. */
# define TEST_SESS_REG(name, caCrt, \
serverCrt, clientCrt, \
expectServerFail, expectClientFail, \
@@ -296,7 +434,7 @@ int main(int argc, char **argv)
hostname, wildcards \
}; \
g_test_add_data_func("/qcrypto/tlssession/" # name, \
- &name, test_crypto_tls_session); \
+ &name, test_crypto_tls_session_x509); \
# define TEST_SESS_REG_EXT(name, serverCaCrt, clientCaCrt, \
@@ -309,7 +447,7 @@ int main(int argc, char **argv)
hostname, wildcards \
}; \
g_test_add_data_func("/qcrypto/tlssession/" # name, \
- &name, test_crypto_tls_session); \
+ &name, test_crypto_tls_session_x509); \
/* A perfect CA, perfect client & perfect server */
@@ -518,6 +656,7 @@ int main(int argc, char **argv)
test_tls_discard_cert(&clientcertlevel2breq);
unlink(WORKDIR "cacertchain-sess.pem");
+ test_tls_psk_cleanup(PSKFILE);
test_tls_cleanup(KEYFILE);
rmdir(WORKDIR);
diff --git a/tests/test-qga.c b/tests/test-qga.c
index daadf22ea3..d638b1571a 100644
--- a/tests/test-qga.c
+++ b/tests/test-qga.c
@@ -886,6 +886,54 @@ static void test_qga_guest_exec_invalid(gconstpointer fix)
qobject_unref(ret);
}
+static void test_qga_guest_get_host_name(gconstpointer fix)
+{
+ const TestFixture *fixture = fix;
+ QDict *ret, *val;
+
+ ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-host-name'}");
+ g_assert_nonnull(ret);
+ qmp_assert_no_error(ret);
+
+ val = qdict_get_qdict(ret, "return");
+ g_assert(qdict_haskey(val, "host-name"));
+
+ qobject_unref(ret);
+}
+
+static void test_qga_guest_get_timezone(gconstpointer fix)
+{
+ const TestFixture *fixture = fix;
+ QDict *ret, *val;
+
+ ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-timezone'}");
+ g_assert_nonnull(ret);
+ qmp_assert_no_error(ret);
+
+ /* Make sure there's at least offset */
+ val = qdict_get_qdict(ret, "return");
+ g_assert(qdict_haskey(val, "offset"));
+
+ qobject_unref(ret);
+}
+
+static void test_qga_guest_get_users(gconstpointer fix)
+{
+ const TestFixture *fixture = fix;
+ QDict *ret;
+ QList *val;
+
+ ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-users'}");
+ g_assert_nonnull(ret);
+ qmp_assert_no_error(ret);
+
+ /* There is not much to test here */
+ val = qdict_get_qlist(ret, "return");
+ g_assert_nonnull(val);
+
+ qobject_unref(ret);
+}
+
static void test_qga_guest_get_osinfo(gconstpointer data)
{
TestFixture fixture;
@@ -980,6 +1028,12 @@ int main(int argc, char **argv)
test_qga_guest_exec_invalid);
g_test_add_data_func("/qga/guest-get-osinfo", &fix,
test_qga_guest_get_osinfo);
+ g_test_add_data_func("/qga/guest-get-host-name", &fix,
+ test_qga_guest_get_host_name);
+ g_test_add_data_func("/qga/guest-get-timezone", &fix,
+ test_qga_guest_get_timezone);
+ g_test_add_data_func("/qga/guest-get-users", &fix,
+ test_qga_guest_get_users);
ret = g_test_run();
diff --git a/tests/test-qmp-cmds.c b/tests/test-qmp-cmds.c
index afb338a61e..ba41a6161e 100644
--- a/tests/test-qmp-cmds.c
+++ b/tests/test-qmp-cmds.c
@@ -12,6 +12,18 @@
static QmpCommandList qmp_commands;
+#if defined(TEST_IF_STRUCT) && defined(TEST_IF_CMD)
+UserDefThree *qmp_TestIfCmd(TestIfStruct *foo, Error **errp)
+{
+ return NULL;
+}
+#endif
+
+UserDefThree *qmp_TestCmdReturnDefThree(Error **errp)
+{
+ return NULL;
+}
+
void qmp_user_def_cmd(Error **errp)
{
}