[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v2 3/3] qtest: add migrate-test
From: |
Jason Baron |
Subject: |
[Qemu-devel] [PATCH v2 3/3] qtest: add migrate-test |
Date: |
Thu, 20 Dec 2012 12:14:50 -0500 |
From: Jason Baron <address@hidden>
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.
Signed-off-by: Jason Baron <address@hidden>
---
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
diff --git a/tests/Makefile b/tests/Makefile
index 1756b47..3f0c5a2 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -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
diff --git a/tests/libqtest.c b/tests/libqtest.c
index 994cd2f..28cbea9 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -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 QTestState
gchar *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;
+}
diff --git a/tests/libqtest.h b/tests/libqtest.h
index 972ba5d..47d189b 100644
--- a/tests/libqtest.h
+++ b/tests/libqtest.h
@@ -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) \
)
/**
diff --git a/tests/migrate-test.c b/tests/migrate-test.c
new file mode 100644
index 0000000..80ef815
--- /dev/null
+++ b/tests/migrate-test.c
@@ -0,0 +1,68 @@
+/*
+ * Migration tests
+ *
+ * Copyright Red Hat, Inc. 2012
+ *
+ * Authors:
+ * Jason Baron <address@hidden>
+ *
+ * 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();
+ g_assert(false);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+ gchar *src_cmdline;
+ gchar *dst_cmdline;
+ const char *dst_uri = "tcp:0:4444";
+
+ 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