diff --git a/tests/Makefile b/tests/Makefile
index 30a101d..d50dff0 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) qstring.o
 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) qstring.o
 tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o tests/libqtest.o $(trace-obj-y) qstring.o
+tests/migrate-test$(EXESUF): tests/migrate-test.o $(test-qapi-obj-y) $(qom-obj-y)
 
 # QTest rules
 
diff --git a/tests/migrate-test.c b/tests/migrate-test.c
new file mode 100644
index 0000000..c62d5af
--- /dev/null
+++ b/tests/migrate-test.c
@@ -0,0 +1,140 @@
+/*
+ * Migration tests
+ *
+ * Copyright Red Hat, Inc. 2012
+ *
+ * Authors:
+ *  Jason Baron   <jbaron@redhat.com>
+ *
+ * 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>
+
+#include "qjson.h"
+#include "error.h"
+#include "qemu/object.h"
+#include "qdict.h"
+#include "qbool.h"
+
+#define migrate_assert(cond) \
+    if (!(cond)) {           \
+        migrate_cleanup();   \
+        fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, #cond); \
+        abort();             \
+    }                        \
+
+static QTestState *mach_a;
+static QTestState *mach_b;
+
+static void migrate_cleanup(void)
+{
+    if (mach_a) {
+        qtest_quit(mach_a);
+    }
+    if (mach_b) {
+        qtest_quit(mach_b);
+    }
+}
+
+static int expected_qobject(QObject *obj, qtype_code type)
+{
+    if (!obj) {
+        return 0;
+    }
+    return (qobject_type(obj) == type);
+}
+
+/*
+ * Return vals:
+ * 1: yes
+ * 0: no
+ * -1: 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 (!expected_qobject(resp_obj, QTYPE_QDICT)) {
+        ret = -1;
+        goto out;
+    }
+
+    ret_obj = qdict_get(qobject_to_qdict(resp_obj), "return");
+    if (!expected_qobject(ret_obj, QTYPE_QDICT)) {
+        ret = -1;
+        goto out;
+    }
+
+    run_obj = qdict_get(qobject_to_qdict(ret_obj), "running");
+    if (!expected_qobject(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)
+
+static void migrate_a_to_b(void)
+{
+    int a_run = 0;
+    int b_run = 0;
+    int iter = 0;
+
+    /* is running on A ? */
+    migrate_assert(is_running(mach_a));
+
+    /* do migrate */
+    qtest_qmp(mach_a, "{ 'execute': 'migrate',"
+              "'arguments': { 'uri': 'tcp:0:4444' } }", NULL);
+
+    while (iter < SLEEP_MAX) {
+        a_run = is_running(mach_a);
+        b_run = is_running(mach_b);
+        if ((a_run == 0) && (b_run == 1)) {
+            break;
+        }
+        sleep(SLEEP_INTERVAL);
+        iter += SLEEP_INTERVAL;
+    }
+    migrate_assert((a_run == 0) && (b_run == 1));
+}
+
+int main(int argc, char **argv)
+{
+    int ret;
+
+    g_test_init(&argc, &argv, NULL);
+
+    mach_a = qtest_start("-display none -machine pc");
+    mach_b = qtest_start("-display none -machine pc -incoming tcp:0:4444");
+
+    qtest_add_func("/migrate/a-to-b", migrate_a_to_b);
+    ret = g_test_run();
+
+    migrate_cleanup();
+    return ret;
+}
