qtest: add migration testing
v2 cover qtest: add migration testing
Hi,
Add a basic qtest for migration testing. Currently, it just tests a migrate of machine 'pc' on the same host. Would be nice to extend to multiple machine versions, but that requires multiple binaries, which could be done, but is perhaps a bit awkward from qtest? Testing different machine versions within the same binary doesn't seem like a real world test case to me. Currently, the test aborts, if the migrate takes more than 2 minutes.
In any case, the test currently fails for q35, since ahci migration suport isn't in place. Thus, I intend to add q35 testing here, once those ahci migration patches are accepted.
Thanks,
-Jason
v2:
* move core migration functions to libqtest.c
* simplify Makefile dependencies
* use 'mkdtemp()' instead of child pid to identify qemu instances
Jason Baron (3):
qtest: Enable creation of multiple qemu instances
qtest: extend qtest_qmp() to fill in the reply
qtest: add migrate-test
tests/Makefile | 4 +- tests/libqtest.c | 130 ++++++++++++++++++++++++++++++++++++++++++++------ tests/libqtest.h | 30 ++++++++++-- tests/migrate-test.c | 68 ++++++++++++++++++++++++++ 4 files changed, 212 insertions(+), 20 deletions(-) create mode 100644 tests/migrate-test.c
PATCH v2 1/3 qtest: Enable creation of multiple qemu instances
From: Jason Baron <[email protected]>
Currently, the qtest harness can only spawn 1 qemu instance at a time because the parent pid is used to create the socket files. Use 'mkdtemp()' in combination with the parent pid to avoid conflicts.
--- tests/libqtest.c | 15 +++++++++------ 1 files changed, 9 insertions(+), 6 deletions(-)
tests/libqtest.c +9 -6
@@ -41,6 +41,7 @@ struct QTestStateGString *rx;gchar *pid_file;char *socket_path, *qmp_socket_path; +char *tmp_dir; };#define g_assert_no_errno (ret) do { \
@@ -105,7 +106,6 @@ QTestState *qtest_init(const char *extra_args) {QTestState *s;int sock, qmpsock, ret, i; -gchar *pid_file;gchar *command;const char *qemu_binary;pid_t pid;
@@ -115,9 +115,11 @@ QTestState *qtest_init(const char *extra_args) s =g_malloc (sizeof (*s)); - s->socket_path =g_strdup_printf ("/tmp/qtest-%d.sock" ,getpid ()); - s->qmp_socket_path =g_strdup_printf ("/tmp/qtest-%d.qmp" ,getpid ()); - pid_file =g_strdup_printf ("/tmp/qtest-%d.pid" ,getpid ()); + s->tmp_dir =g_strdup_printf ("/tmp/qtest-%d-XXXXXX" ,getpid ()); +g_assert (mkdtemp (s->tmp_dir) !=NULL ); + s->socket_path =g_strdup_printf ("%s/%s" , s->tmp_dir,"sock" ); + s->qmp_socket_path =g_strdup_printf ("%s/%s" , s->tmp_dir,"qmp" ); + s->pid_file =g_strdup_printf ("%s/%s" , s->tmp_dir,"pid" ); sock =init_socket (s->socket_path); qmpsock =init_socket (s->qmp_socket_path);
@@ -131,7 +133,7 @@ QTestState *qtest_init(const char *extra_args)"-pidfile %s " "-machine accel=qtest " "%s" , qemu_binary, s->socket_path, - s->qmp_socket_path, pid_file, + s->qmp_socket_path, s->pid_file, extra_args ?: ""); ret =system (command);
@@ -143,7 +145,6 @@ QTestState *qtest_init(const char *extra_args) s->qmp_fd =socket_accept (qmpsock); s->rx =g_string_new ("" ); - s->pid_file = pid_file;for (i =0 ; i <MAX_IRQ ; i++) { s->irq_level[i] = false; }
@@ -172,9 +173,11 @@ void qtest_quit(QTestState *s)unlink (s->pid_file);unlink (s->socket_path);unlink (s->qmp_socket_path); +unlink (s->tmp_dir);g_free (s->pid_file);g_free (s->socket_path);g_free (s->qmp_socket_path); +g_free (s->tmp_dir); }static void socket_sendf (int fd,const char *fmt,va_list ap)
Signature · 1 line
1.7.1
Re: [Qemu-devel] [PATCH v2 1/3] qtest: Enable creation of multiple qemu instances
Quoted 4 lines · Jason Baron
From: Jason Baron <[email protected]>
Currently, the qtest harness can only spawn 1 qemu instance at a time because the parent pid is used to create the socket files. Use '
mkdtemp()' in
But mkdtemp() is not available on Win32.
Quoted 60 lines
combination with the parent pid to avoid conflicts.
Signed-off-by Jason Baron <[email protected]>--- tests/libqtest.c | 15 +++++++++------ 1 files changed, 9 insertions(+), 6 deletions(-)tests/libqtest.c +7
-6@@ -41,6 +41,7 @@ struct QTestStateGString *rx;gchar *pid_file;char *socket_path, *qmp_socket_path; +char *tmp_dir; };#define g_assert_no_errno (ret) do { \@@ -105,7 +106,6 @@ QTestState *qtest_init(const char *extra_args) {QTestState *s;int sock, qmpsock, ret, i; -gchar *pid_file;gchar *command;const char *qemu_binary;pid_t pid;@@ -115,9 +115,11 @@ QTestState *qtest_init(const char *extra_args) s =g_malloc (sizeof (*s)); - s->socket_path =g_strdup_printf ("/tmp/qtest-%d.sock" ,getpid ()); - s->qmp_socket_path =g_strdup_printf ("/tmp/qtest-%d.qmp" ,getpid ()); - pid_file =g_strdup_printf ("/tmp/qtest-%d.pid" ,getpid ()); + s->tmp_dir =g_strdup_printf ("/tmp/qtest-%d-XXXXXX" ,getpid ()); +g_assert (mkdtemp (s->tmp_dir) !=NULL ); + s->socket_path =g_strdup_printf ("%s/%s" , s->tmp_dir,"sock" ); + s->qmp_socket_path =g_strdup_printf ("%s/%s" , s->tmp_dir,"qmp" ); + s->pid_file =g_strdup_printf ("%s/%s" , s->tmp_dir,"pid" ); sock =init_socket (s->socket_path); qmpsock =init_socket (s->qmp_socket_path);@@ -131,7 +133,7 @@ QTestState *qtest_init(const char *extra_args)"-pidfile %s " "-machine accel=qtest " "%s" , qemu_binary, s->socket_path, - s->qmp_socket_path, pid_file, + s->qmp_socket_path, s->pid_file, extra_args ?: ""); ret =system (command);@@ -143,7 +145,6 @@ QTestState *qtest_init(const char *extra_args) s->qmp_fd =socket_accept (qmpsock); s->rx =g_string_new ("" ); - s->pid_file = pid_file;for (i =0 ; i <MAX_IRQ ; i++) { s->irq_level[i] = false; }
tests/libqtest.c void qtest_quit(QTestState *s) · line 176
Quoted 4 lines
tests/libqtest.c +1
-0@@ -172,9 +173,11 @@ void qtest_quit(QTestState *s)unlink (s->pid_file);unlink (s->socket_path);unlink (s->qmp_socket_path); +unlink (s->tmp_dir);
-EISDIR, rmdir() would be needed instead.
Quoted 10 lines
tests/libqtest.c +1
-1g_free (s->pid_file);g_free (s->socket_path);g_free (s->qmp_socket_path); +g_free (s->tmp_dir); }static void socket_sendf (int fd,const char *fmt,va_list ap) --1.7.1
Re: [Qemu-devel] [PATCH v2 1/3] qtest: Enable creation of multiple qemu instances
Quoted 7 lines · Blue Swirl
Quoted 4 lines · Jason Baron
From: Jason Baron <[email protected]>
Currently, the qtest harness can only spawn 1 qemu instance at a time because the parent pid is used to create the socket files. Use '
mkdtemp()' inBut
mkdtemp()is not available on Win32.
So this case important even for qtest?
Quoted 55 lines
Quoted 55 lines
combination with the parent pid to avoid conflicts.
Signed-off-by Jason Baron <[email protected]>--- tests/libqtest.c | 15 +++++++++------ 1 files changed, 9 insertions(+), 6 deletions(-)tests/libqtest.c +7
-5@@ -41,6 +41,7 @@ struct QTestStateGString *rx;gchar *pid_file;char *socket_path, *qmp_socket_path; +char *tmp_dir; };#define g_assert_no_errno (ret) do { \@@ -105,7 +106,6 @@ QTestState *qtest_init(const char *extra_args) {QTestState *s;int sock, qmpsock, ret, i; -gchar *pid_file;gchar *command;const char *qemu_binary;pid_t pid;@@ -115,9 +115,11 @@ QTestState *qtest_init(const char *extra_args) s =g_malloc (sizeof (*s)); - s->socket_path =g_strdup_printf ("/tmp/qtest-%d.sock" ,getpid ()); - s->qmp_socket_path =g_strdup_printf ("/tmp/qtest-%d.qmp" ,getpid ()); - pid_file =g_strdup_printf ("/tmp/qtest-%d.pid" ,getpid ()); + s->tmp_dir =g_strdup_printf ("/tmp/qtest-%d-XXXXXX" ,getpid ()); +g_assert (mkdtemp (s->tmp_dir) !=NULL ); + s->socket_path =g_strdup_printf ("%s/%s" , s->tmp_dir,"sock" ); + s->qmp_socket_path =g_strdup_printf ("%s/%s" , s->tmp_dir,"qmp" ); + s->pid_file =g_strdup_printf ("%s/%s" , s->tmp_dir,"pid" ); sock =init_socket (s->socket_path); qmpsock =init_socket (s->qmp_socket_path);@@ -131,7 +133,7 @@ QTestState *qtest_init(const char *extra_args)"-pidfile %s " "-machine accel=qtest " "%s" , qemu_binary, s->socket_path, - s->qmp_socket_path, pid_file, + s->qmp_socket_path, s->pid_file, extra_args ?: ""); ret =system (command);@@ -143,7 +145,6 @@ QTestState *qtest_init(const char *extra_args) s->qmp_fd =socket_accept (qmpsock);
Quoted 13 lines
tests/libqtest.c void qtest_quit(QTestState *s) · line 176
Quoted 10 lines
tests/libqtest.c +1
-1s->rx =g_string_new ("" ); - s->pid_file = pid_file;for (i =0 ; i <MAX_IRQ ; i++) { s->irq_level[i] = false; }@@ -172,9 +173,11 @@ void qtest_quit(QTestState *s)unlink (s->pid_file);unlink (s->socket_path);unlink (s->qmp_socket_path); +unlink (s->tmp_dir);
-EISDIR,rmdir()would be needed instead.
'unlink()' tested fine on Linux. But yes, it might not be as portable.
I looked at tempnam() and mktemp(), but they both generate linker warnings. 'mkstemp()' could be used but its awkward to delete the file right after its created so that bind() can create it. Plus, it could be a greater security risk in that the filename is easier to determine.
We could write our own random file string generator then, if mkdtemp(), isn't ok.
Quoted 10 lines
Quoted 10 lines
tests/libqtest.c +1
-1g_free (s->pid_file);g_free (s->socket_path);g_free (s->qmp_socket_path); +g_free (s->tmp_dir); }static void socket_sendf (int fd,const char *fmt,va_list ap) --1.7.1
Re: [Qemu-devel] [PATCH v2 1/3] qtest: Enable creation of multiple qemu instances
Quoted 10 lines · Jason Baron
Quoted 7 lines · Blue Swirl
Quoted 4 lines · Jason Baron
From: Jason Baron <[email protected]>
Currently, the qtest harness can only spawn 1 qemu instance at a time because the parent pid is used to create the socket files. Use '
mkdtemp()' inBut
mkdtemp()is not available on Win32.So this case important even for qtest?
Well, there's $(EXESUF) handling for qtest also. But it does not seem to build now:
LINK tests/test-thread-pool.exetests/test-thread-pool.o: In function `test_cancel':
/src/qemu/tests/test-thread-pool.c:177: undefined reference to `___sync_val_compare_and_swap_4'tests/test-thread-pool.o: In function `worker_cb':
/src/qemu/tests/test-thread-pool.c:18: undefined reference to `___sync_fetch_and_add_4'
Quoted 72 lines
Quoted 56 lines
Quoted 56 lines
combination with the parent pid to avoid conflicts.
Signed-off-by Jason Baron <[email protected]>--- tests/libqtest.c | 15 +++++++++------ 1 files changed, 9 insertions(+), 6 deletions(-)tests/libqtest.c +7
-5@@ -41,6 +41,7 @@ struct QTestStateGString *rx;gchar *pid_file;char *socket_path, *qmp_socket_path; +char *tmp_dir; };#define g_assert_no_errno (ret) do { \@@ -105,7 +106,6 @@ QTestState *qtest_init(const char *extra_args) {QTestState *s;int sock, qmpsock, ret, i; -gchar *pid_file;gchar *command;const char *qemu_binary;pid_t pid;@@ -115,9 +115,11 @@ QTestState *qtest_init(const char *extra_args) s =g_malloc (sizeof (*s)); - s->socket_path =g_strdup_printf ("/tmp/qtest-%d.sock" ,getpid ()); - s->qmp_socket_path =g_strdup_printf ("/tmp/qtest-%d.qmp" ,getpid ()); - pid_file =g_strdup_printf ("/tmp/qtest-%d.pid" ,getpid ()); + s->tmp_dir =g_strdup_printf ("/tmp/qtest-%d-XXXXXX" ,getpid ()); +g_assert (mkdtemp (s->tmp_dir) !=NULL ); + s->socket_path =g_strdup_printf ("%s/%s" , s->tmp_dir,"sock" ); + s->qmp_socket_path =g_strdup_printf ("%s/%s" , s->tmp_dir,"qmp" ); + s->pid_file =g_strdup_printf ("%s/%s" , s->tmp_dir,"pid" ); sock =init_socket (s->socket_path); qmpsock =init_socket (s->qmp_socket_path);@@ -131,7 +133,7 @@ QTestState *qtest_init(const char *extra_args)"-pidfile %s " "-machine accel=qtest " "%s" , qemu_binary, s->socket_path, - s->qmp_socket_path, pid_file, + s->qmp_socket_path, s->pid_file, extra_args ?: ""); ret =system (command);@@ -143,7 +145,6 @@ QTestState *qtest_init(const char *extra_args) s->qmp_fd =socket_accept (qmpsock);Quoted 13 lines
tests/libqtest.c void qtest_quit(QTestState *s) · line 176
Quoted 10 lines
tests/libqtest.c +1
-1s->rx =g_string_new ("" ); - s->pid_file = pid_file;for (i =0 ; i <MAX_IRQ ; i++) { s->irq_level[i] = false; }@@ -172,9 +173,11 @@ void qtest_quit(QTestState *s)unlink (s->pid_file);unlink (s->socket_path);unlink (s->qmp_socket_path); +unlink (s->tmp_dir);
-EISDIR,rmdir()would be needed instead.'
unlink()' tested fine on Linux. But yes, it might not be as portable.
Quoted 7 lines
I looked at
tempnam()andmktemp(), but they both generate linker warnings. 'mkstemp()' could be used but its awkward to delete the file right after its created so thatbind()can create it. Plus, it could be a greater security risk in that the filename is easier to determine.We could write our own random file string generator then, if
mkdtemp(), isn't ok.
Or introduce qemu_mkdtemp() which resolves either to mkdtemp() or to a custom implementation:
http://stackoverflow.com/questions/278439/creating-a-temporary-directory-in-windows
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
tests/libqtest.c +1
-1g_free (s->pid_file);g_free (s->socket_path);g_free (s->qmp_socket_path); +g_free (s->tmp_dir); }static void socket_sendf (int fd,const char *fmt,va_list ap) --1.7.1
Re: [Qemu-devel] [PATCH v2 1/3] qtest: Enable creation of multiple qemu instances
In reply to Jason BaronQuoted 3 lines · Jason Baron
Quoted 2 lines · Blue Swirl
Quoted 1 line · Jason Baron
From: Jason Baron <[email protected]>
[...]
Quoted 10 lines
Quoted 8 lines
tests/libqtest.c void qtest_quit(QTestState *s) · line 176
Quoted 5 lines
tests/libqtest.c +1
-0@@ -172,9 +173,11 @@ void qtest_quit(QTestState *s)unlink (s->pid_file);unlink (s->socket_path);unlink (s->qmp_socket_path); +unlink (s->tmp_dir);
-EISDIR,rmdir()would be needed instead.'
unlink()' tested fine on Linux. But yes, it might not be as portable.
s/might not be as/isn't/
SUSv7:
[EPERM]
The file named by path is a directory, and either the calling process does not have appropriate privileges, or the implementation prohibits using unlink() on directories.
[...]
PATCH v2 2/3 qtest: extend qtest_qmp() to fill in the reply
In reply to Jason BaronFrom: Jason Baron <[email protected]>
Introduce:
Add void qtest_qmp_resp(QTestState *s, QString *resp, const char *fmt, ...)
which allows a response string to be filled in.
--- tests/Makefile | 2 +- tests/libqtest.c | 17 ++++++++++------- tests/libqtest.h | 15 +++++++++++++-- 3 files changed, 24 insertions(+), 10 deletions(-)
tests/Makefile +1 -1
@@ -85,7 +85,7 @@ TARGETS=$(patsubst %-softmmu,%, $(filter %-softmmu,$(TARGET_DIRS))) QTEST_TARGETS=$(foreach TARGET,$(TARGETS), $(if $(check-qtest-$(TARGET)-y), $(TARGET),)) check-qtest-$(CONFIG_POSIX)=$(foreach TARGET,$(TARGETS), $(check-qtest-$(TARGET)-y)) -qtest-obj-y = tests/libqtest.o $(oslib-obj-y) libqemustub.a +qtest-obj-y = tests/libqtest.o $(oslib-obj-y) libqemustub.a $(test-qapi-obj-y) $(qom-obj-y) $(check-qtest-y): $(qtest-obj-y) .PHONY: check-help
tests/libqtest.c +10 -7
@@ -288,7 +288,7 @@ redo:return words; } -void qtest_qmp (QTestState *s,const char *fmt, ...) +void qtest_qmp_resp (QTestState *s,QString *resp,const char *fmt, ...) {va_list ap;bool has_reply = false;
@@ -313,16 +313,19 @@ void qtest_qmp(QTestState *s, const char *fmt, ...)fprintf (stderr,"Broken pipe\n" );exit (1 ); } - -switch (c) { -case '{' : +if (c =='{' ) { nesting++; has_reply = true; -break ; -case '}' : + } +if (c =='}' ) { nesting--; -break ; } +if (has_reply && resp) { +qstring_append_chr (resp, c); + } + } +if (has_reply && resp) { +qstring_append_chr (resp,'\0' ); } }
tests/libqtest.h +13 -2
@@ -18,6 +18,7 @@#include <stdint.h> #include <stdbool.h> #include <sys/types.h> +#include "qstring.h" typedef struct QTestState QTestState ;
@@ -38,13 +39,14 @@ QTestState *qtest_init(const char *extra_args);void qtest_quit (QTestState *s);/** -* qtest_qmp: +* qtest_qmp_resp: * @s: QTestState instance to operate on. +* @resp: Fills in response string if provided * @fmt...: QMP message to send to qemu * * Sends a QMP message to QEMU */ -void qtest_qmp (QTestState *s,const char *fmt, ...); +void qtest_qmp_resp (QTestState *s,QString *resp,const char *fmt, ...);/** * qtest_get_irq:
@@ -349,4 +351,13 @@ void qtest_add_func(const char *str, void (*fn));*/ #define clock_set (val) qtest_clock_set(global_qtest, val) +/** +* qtest_qmp: +* @s: QTestState instance to operate on. +* @fmt...: QMP message to send to qemu +* +* Sends a QMP message to QEMU +*/ +#define qtest_qmp (s, fmt, ...) qtest_qmp_resp(s, NULL, fmt, ## __VA_ARGS__) +#endif
Signature · 1 line
1.7.1
Re: [Qemu-devel] [PATCH v2 2/3] qtest: extend qtest_qmp() to fill in the reply
Quoted 6 lines · Jason Baron
From: Jason Baron <[email protected]>
Introduce:
Add void
qtest_qmp_resp(QTestState *s, QString *resp, const char *fmt, ...)
Any reason to not just return a QString?
Also, why not do the parsing in this function and just return a QObject of the result?
Regards,
Anthony Liguori
Quoted 107 lines
which allows a response string to be filled in.
Signed-off-by Jason Baron <[email protected]>--- tests/Makefile | 2 +- tests/libqtest.c | 17 ++++++++++------- tests/libqtest.h | 15 +++++++++++++-- 3 files changed, 24 insertions(+), 10 deletions(-)tests/Makefile +1
-1@@ -85,7 +85,7 @@ TARGETS=$(patsubst %-softmmu,%, $(filter %-softmmu,$(TARGET_DIRS))) QTEST_TARGETS=$(foreach TARGET,$(TARGETS), $(if $(check-qtest-$(TARGET)-y), $(TARGET),)) check-qtest-$(CONFIG_POSIX)=$(foreach TARGET,$(TARGETS), $(check-qtest-$(TARGET)-y)) -qtest-obj-y = tests/libqtest.o $(oslib-obj-y) libqemustub.a +qtest-obj-y = tests/libqtest.o $(oslib-obj-y) libqemustub.a $(test-qapi-obj-y) $(qom-obj-y) $(check-qtest-y): $(qtest-obj-y) .PHONY: check-helptests/libqtest.c +10
-7@@ -288,7 +288,7 @@ redo:return words; } -void qtest_qmp (QTestState *s,const char *fmt, ...) +void qtest_qmp_resp (QTestState *s,QString *resp,const char *fmt, ...) {va_list ap;bool has_reply = false;@@ -313,16 +313,19 @@ void qtest_qmp(QTestState *s, const char *fmt, ...)fprintf (stderr,"Broken pipe\n" );exit (1 ); } - -switch (c) { -case '{' : +if (c =='{' ) { nesting++; has_reply = true; -break ; -case '}' : + } +if (c =='}' ) { nesting--; -break ; } +if (has_reply && resp) { +qstring_append_chr (resp, c); + } + } +if (has_reply && resp) { +qstring_append_chr (resp,'\0' ); } }tests/libqtest.h +13
-2@@ -18,6 +18,7 @@#include <stdint.h> #include <stdbool.h> #include <sys/types.h> +#include "qstring.h" typedef struct QTestState QTestState ;@@ -38,13 +39,14 @@ QTestState *qtest_init(const char *extra_args);void qtest_quit (QTestState *s);/** -* qtest_qmp: +* qtest_qmp_resp: * @s: QTestState instance to operate on. +* @resp: Fills in response string if provided * @fmt...: QMP message to send to qemu * * Sends a QMP message to QEMU */ -void qtest_qmp (QTestState *s,const char *fmt, ...); +void qtest_qmp_resp (QTestState *s,QString *resp,const char *fmt, ...);/** * qtest_get_irq: @@ -349,4 +351,13 @@ void qtest_add_func(const char *str, void (*fn));*/ #define clock_set (val) qtest_clock_set(global_qtest, val) +/** +* qtest_qmp: +* @s: QTestState instance to operate on. +* @fmt...: QMP message to send to qemu +* +* Sends a QMP message to QEMU +*/ +#define qtest_qmp (s, fmt, ...) qtest_qmp_resp(s, NULL, fmt, ## __VA_ARGS__) +#endif Signature · 1 line
1.7.1
PATCH v2 3/3 qtest: add migrate-test
In reply to Jason BaronFrom: Jason Baron <[email protected]>
Tests a single 'pc' machine migration on the same host.
Would be nice to extend the test matrix to various machine versions, but that requires building multiple qemu binaries, which is a bit awkward in the context of qtest. Testing migration between different machine versions with the same binary doesn't seem too useful.
--- tests/Makefile | 2 + tests/libqtest.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++- tests/libqtest.h | 15 +++++++- tests/migrate-test.c | 68 ++++++++++++++++++++++++++++++++++ 4 files changed, 179 insertions(+), 4 deletions(-) create mode 100644 tests/migrate-test.c
tests/Makefile +2 -0
@@ -25,6 +25,7 @@ check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh check-qtest-i386-y = tests/fdc-test$(EXESUF) check-qtest-i386-y += tests/hd-geo-test$(EXESUF) check-qtest-i386-y += tests/rtc-test$(EXESUF) +check-qtest-i386-y += tests/migrate-test$(EXESUF) check-qtest-x86_64-y = $(check-qtest-i386-y) check-qtest-sparc-y = tests/m48t59-test$(EXESUF) check-qtest-sparc64-y = tests/m48t59-test$(EXESUF)
@@ -78,6 +79,7 @@ tests/rtc-test$(EXESUF): tests/rtc-test.o $(trace-obj-y) tests/m48t59-test$(EXESUF): tests/m48t59-test.o $(trace-obj-y) tests/fdc-test$(EXESUF): tests/fdc-test.o tests/libqtest.o $(trace-obj-y) tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o tests/libqtest.o $(trace-obj-y) +tests/migrate-test$(EXESUF): tests/migrate-test.o # QTest rules
tests/libqtest.c +96 -2
137 lines not on this page · raw message
tests/libqtest.h +13 -2
@@ -27,8 +27,9 @@ extern QTestState *global_qtest;/** * qtest_init: * @extra_args: other arguments to pass to QEMU. +* @incoming_uri: used for incoming migration. */ -QTestState *qtest_init (const char *extra_args); +QTestState *qtest_init (const char *extra_args,const char *incoming_uri);/** * qtest_quit:
@@ -207,6 +208,16 @@ const char *qtest_get_arch(void);void qtest_add_func (const char *str,void (*fn));/** +* test_migrate: +* @mach_src: QTestState source. +* @mach_dst: QTestState destination. +* +* Migrate a VM from mach_src to mach_dst. +* Returns 0 on success, -1 on failure. +*/ +int test_migrate (QTestState *mach_src,QTestState *mach_dst); + +/** * qtest_start: * @args: other arguments to pass to QEMU *
@@ -214,7 +225,7 @@ void qtest_add_func(const char *str, void (*fn));* The global variable is used by "shortcut" macros documented below. */ #define qtest_start (args) ( \ - global_qtest = qtest_init((args)) \ + global_qtest = qtest_init((args), NULL) \ )/**
tests/migrate-test.c new file +68 -0
68 lines not on this page · raw message
Signature · 1 line
1.7.1
Re: [Qemu-devel] [PATCH v2 3/3] qtest: add migrate-test
Quoted 8 lines · Jason Baron
From: Jason Baron <[email protected]>
Tests a single 'pc' machine migration on the same host.
Would be nice to extend the test matrix to various machine versions, but that requires building multiple qemu binaries, which is a bit awkward in the context of qtest. Testing migration between different machine versions with the same binary doesn't seem too useful.
We could test migration between TCG, Xen and KVM if two of those are available.
Quoted 264 lines
Signed-off-by Jason Baron <[email protected]>--- tests/Makefile | 2 + tests/libqtest.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++- tests/libqtest.h | 15 +++++++- tests/migrate-test.c | 68 ++++++++++++++++++++++++++++++++++ 4 files changed, 179 insertions(+), 4 deletions(-) create mode 100644 tests/migrate-test.ctests/Makefile +2
-0@@ -25,6 +25,7 @@ check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh check-qtest-i386-y = tests/fdc-test$(EXESUF) check-qtest-i386-y += tests/hd-geo-test$(EXESUF) check-qtest-i386-y += tests/rtc-test$(EXESUF) +check-qtest-i386-y += tests/migrate-test$(EXESUF) check-qtest-x86_64-y = $(check-qtest-i386-y) check-qtest-sparc-y = tests/m48t59-test$(EXESUF) check-qtest-sparc64-y = tests/m48t59-test$(EXESUF)@@ -78,6 +79,7 @@ tests/rtc-test$(EXESUF): tests/rtc-test.o $(trace-obj-y) tests/m48t59-test$(EXESUF): tests/m48t59-test.o $(trace-obj-y) tests/fdc-test$(EXESUF): tests/fdc-test.o tests/libqtest.o $(trace-obj-y) tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o tests/libqtest.o $(trace-obj-y) +tests/migrate-test$(EXESUF): tests/migrate-test.o # QTest rulestests/libqtest.c +96
-2@@ -28,6 +28,9 @@#include "compiler.h" #include "osdep.h" +#include "qjson.h" +#include "qdict.h" +#include "qbool.h" #define MAX_IRQ 256@@ -42,6 +45,8 @@ struct QTestStategchar *pid_file;char *socket_path, *qmp_socket_path;char *tmp_dir; +/* uri to use for incoming migration */ +char *incoming_uri; };#define g_assert_no_errno (ret) do { \@@ -102,7 +107,7 @@ static pid_t qtest_qemu_pid(QTestState *s)return pid; } -QTestState *qtest_init (const char *extra_args) +QTestState *qtest_init (const char *extra_args,const char *incoming_uri) {QTestState *s;int sock, qmpsock, ret, i;@@ -113,13 +118,14 @@ QTestState *qtest_init(const char *extra_args) qemu_binary =getenv ("QTEST_QEMU_BINARY" );g_assert (qemu_binary !=NULL ); - s =g_malloc (sizeof (*s)); + s =g_malloc0 (sizeof (*s)); s->tmp_dir =g_strdup_printf ("/tmp/qtest-%d-XXXXXX" ,getpid ());g_assert (mkdtemp (s->tmp_dir) !=NULL ); s->socket_path =g_strdup_printf ("%s/%s" , s->tmp_dir,"sock" ); s->qmp_socket_path =g_strdup_printf ("%s/%s" , s->tmp_dir,"qmp" ); s->pid_file =g_strdup_printf ("%s/%s" , s->tmp_dir,"pid" ); + s->incoming_uri =g_strdup (incoming_uri); sock =init_socket (s->socket_path); qmpsock =init_socket (s->qmp_socket_path);@@ -178,6 +184,7 @@ void qtest_quit(QTestState *s)g_free (s->socket_path);g_free (s->qmp_socket_path);g_free (s->tmp_dir); +g_free (s->incoming_uri); }static void socket_sendf (int fd,const char *fmt,va_list ap)@@ -482,3 +489,90 @@ void qtest_memwrite(QTestState *s, uint64_t addr, const void *data, size_t size)qtest_sendf (s,"\n" );qtest_rsp (s,0 ); } + +/** +* is_running: +* @mch: QTestState instance to check. +* +* Returns 1, if mch is running, 0 if its not running. -1 means retry. +*/ +static int is_running (QTestState *mch) +{ +QString *resp =qstring_new (); +QObject *resp_obj; +QObject *ret_obj; +QObject *run_obj; +int ret; + + resp =qstring_new (); +qtest_qmp_resp (mch, resp,"{ 'execute': 'query-status' }" ,NULL ); + + resp_obj =qobject_from_json (qstring_get_str (resp)); +if ((!resp_obj) || (qobject_type (resp_obj) !=QTYPE_QDICT )) { + ret =-1 ; + goto out; + } + + ret_obj =qdict_get (qobject_to_qdict (resp_obj),"return" ); +if ((!ret_obj) || (qobject_type (ret_obj) !=QTYPE_QDICT )) { + ret =-1 ; + goto out; + } + + run_obj =qdict_get (qobject_to_qdict (ret_obj),"running" ); +if ((!run_obj) || (qobject_type (run_obj) !=QTYPE_QBOOL )) { + ret =-1 ; + goto out; + } + ret =qbool_get_int (qobject_to_qbool (run_obj)); + +out: +qobject_decref (resp_obj); +QDECREF (resp); +return ret; +} + +#define SLEEP_INTERVAL 2 +/* Abort after 2 minutes */ +#define SLEEP_MAX (60 * 2) + +int test_migrate (QTestState *mach_src,QTestState *mach_dst) +{ +int src_run =0 ; +int dst_run =0 ; +int iter =0 ; +gchar *migrate_str; + +if (!mach_dst->incoming_uri) { +fprintf (stderr,"do_migrate: Error: mach_dst->incoming_uri not set\n" ); +return -1 ; + } + +/* is running on mach_src ? */ +if (is_running (mach_src) !=1 ) { +fprintf (stderr,"do_migrate: Error: not running on src\n" ); +return -1 ; + } + +/* do migrate */ + migrate_str =g_strdup_printf ("{ 'execute': 'migrate'," +"'arguments': { 'uri': '%s' } }" , + mach_dst->incoming_uri); +qtest_qmp (mach_src, migrate_str,NULL ); +g_free (migrate_str); + +while (iter <SLEEP_MAX ) { + src_run =is_running (mach_src); + dst_run =is_running (mach_dst); +if ((src_run ==0 ) && (dst_run ==1 )) { +break ; + } +sleep (SLEEP_INTERVAL ); + iter +=SLEEP_INTERVAL ; + } +if ((src_run !=0 ) || (dst_run !=1 )) { +fprintf (stderr,"do_migrate: Error: migration failed\n" ); +return -1 ; + } +return 0 ; +}tests/libqtest.h +13
-2@@ -27,8 +27,9 @@ extern QTestState *global_qtest;/** * qtest_init: * @extra_args: other arguments to pass to QEMU. +* @incoming_uri: used for incoming migration. */ -QTestState *qtest_init (const char *extra_args); +QTestState *qtest_init (const char *extra_args,const char *incoming_uri);/** * qtest_quit: @@ -207,6 +208,16 @@ const char *qtest_get_arch(void);void qtest_add_func (const char *str,void (*fn));/** +* test_migrate: +* @mach_src: QTestState source. +* @mach_dst: QTestState destination. +* +* Migrate a VM from mach_src to mach_dst. +* Returns 0 on success, -1 on failure. +*/ +int test_migrate (QTestState *mach_src,QTestState *mach_dst); + +/** * qtest_start: * @args: other arguments to pass to QEMU * @@ -214,7 +225,7 @@ void qtest_add_func(const char *str, void (*fn));* The global variable is used by "shortcut" macros documented below. */ #define qtest_start (args) ( \ - global_qtest = qtest_init((args)) \ + global_qtest = qtest_init((args), NULL) \ )/** tests/migrate-test.c new file +40
-0@@ -0,0 +1,68 @@ +/* +* Migration tests +* +* Copyright Red Hat, Inc. 2012 +* +* Authors: +* Jason Baron <[email protected]> +* +* This work is licensed under the terms of the GNU GPL, version 2 or later. +* See the COPYING file in the top-level directory. +* +*/ +#include "libqtest.h" + +#include <glib.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +static QTestState *mach_src; +static QTestState *mach_dst; + +static void migrate_cleanup (void ) +{ +if (mach_src) { +qtest_quit (mach_src); + } +if (mach_dst) { +qtest_quit (mach_dst); + } +} + +static void test_migration (void ) +{ +int ret; + + ret =test_migrate (mach_src, mach_dst); +if (ret) { +migrate_cleanup ();
tests/migrate-test.c line 50
Quoted 10 lines
tests/migrate-test.c new file +10
-0+g_assert (false); + } +} + +int main (int argc,char **argv) +{ +int ret; +gchar *src_cmdline; +gchar *dst_cmdline; +const char *dst_uri ="tcp:0:4444" ;
Maybe use a random port and localhost.
Quoted 21 lines
tests/migrate-test.c new file +18
-1+ +g_test_init (&argc, &argv,NULL ); + + src_cmdline =g_strdup ("-display none -machine pc" ); + mach_src =qtest_init (src_cmdline,NULL ); + + dst_cmdline =g_strdup_printf ("%s -incoming %s" , src_cmdline, dst_uri); + mach_dst =qtest_init (dst_cmdline, dst_uri); + +g_free (src_cmdline); +g_free (dst_cmdline); + +qtest_add_func ("/migrate/src-to-dst" , test_migration); + ret =g_test_run (); + +migrate_cleanup (); +return ret; +} --1.7.1