Message ID | 09d47ca1eb9dc1391d68d82f3aebd6831328f182.1355435056.git.jbaron@redhat.com |
---|---|
State | New |
Headers | show |
----- Messaggio originale ----- > Da: "Jason Baron" <jbaron@redhat.com> > A: qemu-devel@nongnu.org > Cc: aliguori@us.ibm.com, kwolf@redhat.com, pbonzini@redhat.com, quintela@redhat.com > Inviato: Giovedì, 13 dicembre 2012 23:02:22 > Oggetto: [PATCH 3/3] qtest: add migrate-test > > From: Jason Baron <jbaron@redhat.com> > > Tests a single 'pc' machine migration on the same host. Currently, > the test > fail for q35 since the ahci controller doesn't yet migrate. Will add > support > for q35 once the ahci support is accepted. > > 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 <jbaron@redhat.com> > --- > tests/Makefile | 2 + > tests/migrate-test.c | 140 > ++++++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 142 insertions(+), 0 deletions(-) > create mode 100644 tests/migrate-test.c > > 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) Do you think this function could be turned into a libqtest call? It would take mach_a as an argument, add -incoming tcp:localhost:4444 to the command line of mach_a, use that to spawn mach_b, and return mach_b as the return value (or perhaps change mach_a to refer to the new machine). The reason is that I can anticipate having many migration qtests, at least one for every subsection we ever had to add. Paolo > +{ > + 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; > +} > -- > 1.7.1 > >
On Fri, Dec 14, 2012 at 03:08:21AM -0500, Paolo Bonzini wrote: > > Tests a single 'pc' machine migration on the same host. Currently, > > the test > > fail for q35 since the ahci controller doesn't yet migrate. Will add > > support > > for q35 once the ahci support is accepted. > > > > 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 <jbaron@redhat.com> > > --- > > tests/Makefile | 2 + > > tests/migrate-test.c | 140 > > ++++++++++++++++++++++++++++++++++++++++++++++++++ > > 2 files changed, 142 insertions(+), 0 deletions(-) > > create mode 100644 tests/migrate-test.c > > > > 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) > > Do you think this function could be turned into a libqtest call? Seems like a good idea. > It would take mach_a as an argument, add -incoming tcp:localhost:4444 > to the command line of mach_a, use that to spawn mach_b, and why add to mach_a? I thought -incoming is just for the destination. > return mach_b as the return value (or perhaps change mach_a to > refer to the new machine). I think it makes sense for the caller to create and pass the machines and then just call a library function to do the migrate. That way the caller 'owns' the machines. But maybe I'm missing something. > > The reason is that I can anticipate having many migration qtests, > at least one for every subsection we ever had to add. > > Paolo > > > +{ > > + 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; > > +} > > -- > > 1.7.1 > > > >
> > Do you think this function could be turned into a libqtest call? > > Seems like a good idea. > > > It would take mach_a as an argument, add -incoming > > tcp:localhost:4444 > > to the command line of mach_a, use that to spawn mach_b, and > > why add to mach_a? I thought -incoming is just for the destination. Yep. Tack it at the end of mach_a's command line (actually at the end of the parameter of qtest_start) and use the result to start mach_b. The command-lines for the two machines must match (apart from -incoming of course), it's not necessary to pass it twice. > > return mach_b as the return value (or perhaps change mach_a to > > refer to the new machine). > > I think it makes sense for the caller to create and pass the machines > and then just call a library function to do the migrate. That way the > caller 'owns' the machines. But maybe I'm missing something. Yeah, owning the machines makes sense. In this case migration would just be a constructor for QTestState. The alternative is to kill mach_a during migration and only proceed with mach_b, since mach_a is effectively not going to be used. Paolo
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; +}