[Qemu-devel] [PATCH v2 3/3] qtest: add migrate-test

2012-12-20 Thread Jason Baron
From: Jason Baron 

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 
---
 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-XX", 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 runnin

Re: [Qemu-devel] [PATCH v2 3/3] qtest: add migrate-test

2012-12-20 Thread Blue Swirl
On Thu, Dec 20, 2012 at 5:14 PM, Jason Baron  wrote:
> From: Jason Baron 
>
> 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.

>
> Signed-off-by: Jason Baron 
> ---
>  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-XX", 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(QTe