diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/qtest/migration/cpr-tests.c | 133 | ||||
-rw-r--r-- | tests/unit/test-vmstate.c | 83 |
2 files changed, 204 insertions, 12 deletions
diff --git a/tests/qtest/migration/cpr-tests.c b/tests/qtest/migration/cpr-tests.c index c4ce60f..9388ad6 100644 --- a/tests/qtest/migration/cpr-tests.c +++ b/tests/qtest/migration/cpr-tests.c @@ -113,6 +113,138 @@ static void test_mode_transfer_defer(void) test_mode_transfer_common(true); } +static void set_cpr_exec_args(QTestState *who, MigrateCommon *args) +{ + g_autofree char *qtest_from_args = NULL; + g_autofree char *from_args = NULL; + g_autofree char *to_args = NULL; + g_autofree char *exec_args = NULL; + g_auto(GStrv) argv = NULL; + char *from_str, *src, *dst; + int ret; + + /* + * hide_stderr appends "2>/dev/null" to the command line, but cpr-exec + * passes the command-line words to execv, not to the shell, so suppress it + * here. fd 2 was already bound in the source VM, and execv preserves it. + */ + g_assert(args->start.hide_stderr == false); + + ret = migrate_args(&from_args, &to_args, args->listen_uri, &args->start); + g_assert(!ret); + qtest_from_args = qtest_qemu_args(from_args); + + /* + * The generated args may have been formatted using "%s %s" with empty + * strings, which can produce consecutive spaces, which g_strsplit would + * convert into empty strings. Ditto for leading and trailing space. + * De-dup spaces to avoid that. + */ + + from_str = src = dst = g_strstrip(qtest_from_args); + do { + if (*src != ' ' || src[-1] != ' ') { + *dst++ = *src; + } + } while (*src++); + + exec_args = g_strconcat(qtest_qemu_binary(migration_get_env()->qemu_dst), + " -incoming defer ", from_str, NULL); + argv = g_strsplit(exec_args, " ", -1); + migrate_set_parameter_strv(who, "cpr-exec-command", argv); +} + +static void wait_for_migration_event(QTestState *who, const char *waitfor) +{ + QDict *rsp, *data; + char *status; + bool done = false; + + while (!done) { + rsp = qtest_qmp_eventwait_ref(who, "MIGRATION"); + g_assert(qdict_haskey(rsp, "data")); + data = qdict_get_qdict(rsp, "data"); + g_assert(qdict_haskey(data, "status")); + status = g_strdup(qdict_get_str(data, "status")); + g_assert(strcmp(status, "failed")); + done = !strcmp(status, waitfor); + qobject_unref(rsp); + } +} + +static void test_cpr_exec(MigrateCommon *args) +{ + QTestState *from, *to; + void *data_hook = NULL; + g_autofree char *connect_uri = g_strdup(args->connect_uri); + g_autofree char *filename = g_strdup_printf("%s/%s", tmpfs, + FILE_TEST_FILENAME); + + if (migrate_start(&from, NULL, args->listen_uri, &args->start)) { + return; + } + + /* Source and dest never run concurrently */ + g_assert_false(args->live); + + if (args->start_hook) { + data_hook = args->start_hook(from, NULL); + } + + wait_for_serial("src_serial"); + set_cpr_exec_args(from, args); + migrate_set_capability(from, "events", true); + migrate_qmp(from, NULL, connect_uri, NULL, "{}"); + wait_for_migration_event(from, "completed"); + + to = qtest_init_after_exec(from); + + qtest_qmp_assert_success(to, "{ 'execute': 'migrate-incoming'," + " 'arguments': { " + " 'channels': [ { 'channel-type': 'main'," + " 'addr': { 'transport': 'file'," + " 'filename': %s," + " 'offset': 0 } } ] } }", + filename); + wait_for_migration_complete(to); + + wait_for_resume(to, get_dst()); + /* Device on target is still named src_serial because args do not change */ + wait_for_serial("src_serial"); + + if (args->end_hook) { + args->end_hook(from, to, data_hook); + } + + migrate_end(from, to, args->result == MIG_TEST_SUCCEED); +} + +static void *test_mode_exec_start(QTestState *from, QTestState *to) +{ + assert(!to); + migrate_set_parameter_str(from, "mode", "cpr-exec"); + return NULL; +} + +static void test_mode_exec(void) +{ + g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, + FILE_TEST_FILENAME); + g_autofree char *listen_uri = g_strdup_printf("defer"); + + MigrateCommon args = { + .start.only_source = true, + .start.opts_source = "-machine aux-ram-share=on -nodefaults", + .start.memory_backend = "-object memory-backend-memfd,id=pc.ram,size=%s" + " -machine memory-backend=pc.ram", + .connect_uri = uri, + .listen_uri = listen_uri, + .start_hook = test_mode_exec_start, + }; + + test_cpr_exec(&args); +} + void migration_test_add_cpr(MigrationTestEnv *env) { tmpfs = env->tmpfs; @@ -135,5 +267,6 @@ void migration_test_add_cpr(MigrationTestEnv *env) migration_test_add("/migration/mode/transfer", test_mode_transfer); migration_test_add("/migration/mode/transfer/defer", test_mode_transfer_defer); + migration_test_add("/migration/mode/exec", test_mode_exec); } } diff --git a/tests/unit/test-vmstate.c b/tests/unit/test-vmstate.c index 63f28f2..cadbab3 100644 --- a/tests/unit/test-vmstate.c +++ b/tests/unit/test-vmstate.c @@ -30,6 +30,7 @@ #include "../migration/savevm.h" #include "qemu/module.h" #include "io/channel-file.h" +#include "qapi/error.h" static int temp_fd; @@ -66,9 +67,13 @@ static QEMUFile *open_test_file(bool write) static void save_vmstate(const VMStateDescription *desc, void *obj) { QEMUFile *f = open_test_file(true); + Error *local_err = NULL; /* Save file with vmstate */ - int ret = vmstate_save_state(f, desc, obj, NULL); + int ret = vmstate_save_state(f, desc, obj, NULL, &local_err); + if (ret) { + error_report_err(local_err); + } g_assert(!ret); qemu_put_byte(f, QEMU_VM_EOF); g_assert(!qemu_file_get_error(f)); @@ -108,14 +113,16 @@ static int load_vmstate_one(const VMStateDescription *desc, void *obj, { QEMUFile *f; int ret; + Error *local_err = NULL; f = open_test_file(true); qemu_put_buffer(f, wire, size); qemu_fclose(f); f = open_test_file(false); - ret = vmstate_load_state(f, desc, obj, version); + ret = vmstate_load_state(f, desc, obj, version, &local_err); if (ret) { + error_report_err(local_err); g_assert(qemu_file_get_error(f)); } else{ g_assert(!qemu_file_get_error(f)); @@ -355,6 +362,8 @@ static const VMStateDescription vmstate_versioned = { static void test_load_v1(void) { + Error *local_err = NULL; + int ret; uint8_t buf[] = { 0, 0, 0, 10, /* a */ 0, 0, 0, 30, /* c */ @@ -365,7 +374,10 @@ static void test_load_v1(void) QEMUFile *loading = open_test_file(false); TestStruct obj = { .b = 200, .e = 500, .f = 600 }; - vmstate_load_state(loading, &vmstate_versioned, &obj, 1); + ret = vmstate_load_state(loading, &vmstate_versioned, &obj, 1, &local_err); + if (ret < 0) { + error_report_err(local_err); + } g_assert(!qemu_file_get_error(loading)); g_assert_cmpint(obj.a, ==, 10); g_assert_cmpint(obj.b, ==, 200); @@ -378,6 +390,8 @@ static void test_load_v1(void) static void test_load_v2(void) { + Error *local_err = NULL; + int ret; uint8_t buf[] = { 0, 0, 0, 10, /* a */ 0, 0, 0, 20, /* b */ @@ -391,7 +405,10 @@ static void test_load_v2(void) QEMUFile *loading = open_test_file(false); TestStruct obj; - vmstate_load_state(loading, &vmstate_versioned, &obj, 2); + ret = vmstate_load_state(loading, &vmstate_versioned, &obj, 2, &local_err); + if (ret < 0) { + error_report_err(local_err); + } g_assert_cmpint(obj.a, ==, 10); g_assert_cmpint(obj.b, ==, 20); g_assert_cmpint(obj.c, ==, 30); @@ -425,10 +442,15 @@ static const VMStateDescription vmstate_skipping = { static void test_save_noskip(void) { + Error *local_err = NULL; QEMUFile *fsave = open_test_file(true); TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4, .e = 5, .f = 6, .skip_c_e = false }; - int ret = vmstate_save_state(fsave, &vmstate_skipping, &obj, NULL); + int ret = vmstate_save_state(fsave, &vmstate_skipping, &obj, NULL, + &local_err); + if (ret) { + error_report_err(local_err); + } g_assert(!ret); g_assert(!qemu_file_get_error(fsave)); @@ -447,10 +469,15 @@ static void test_save_noskip(void) static void test_save_skip(void) { + Error *local_err = NULL; QEMUFile *fsave = open_test_file(true); TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4, .e = 5, .f = 6, .skip_c_e = true }; - int ret = vmstate_save_state(fsave, &vmstate_skipping, &obj, NULL); + int ret = vmstate_save_state(fsave, &vmstate_skipping, &obj, NULL, + &local_err); + if (ret) { + error_report_err(local_err); + } g_assert(!ret); g_assert(!qemu_file_get_error(fsave)); @@ -467,6 +494,8 @@ static void test_save_skip(void) static void test_load_noskip(void) { + Error *local_err = NULL; + int ret; uint8_t buf[] = { 0, 0, 0, 10, /* a */ 0, 0, 0, 20, /* b */ @@ -480,7 +509,10 @@ static void test_load_noskip(void) QEMUFile *loading = open_test_file(false); TestStruct obj = { .skip_c_e = false }; - vmstate_load_state(loading, &vmstate_skipping, &obj, 2); + ret = vmstate_load_state(loading, &vmstate_skipping, &obj, 2, &local_err); + if (ret < 0) { + error_report_err(local_err); + } g_assert(!qemu_file_get_error(loading)); g_assert_cmpint(obj.a, ==, 10); g_assert_cmpint(obj.b, ==, 20); @@ -493,6 +525,8 @@ static void test_load_noskip(void) static void test_load_skip(void) { + Error *local_err = NULL; + int ret; uint8_t buf[] = { 0, 0, 0, 10, /* a */ 0, 0, 0, 20, /* b */ @@ -504,7 +538,10 @@ static void test_load_skip(void) QEMUFile *loading = open_test_file(false); TestStruct obj = { .skip_c_e = true, .c = 300, .e = 500 }; - vmstate_load_state(loading, &vmstate_skipping, &obj, 2); + ret = vmstate_load_state(loading, &vmstate_skipping, &obj, 2, &local_err); + if (ret < 0) { + error_report_err(local_err); + } g_assert(!qemu_file_get_error(loading)); g_assert_cmpint(obj.a, ==, 10); g_assert_cmpint(obj.b, ==, 20); @@ -744,6 +781,8 @@ static void test_save_q(void) static void test_load_q(void) { + int ret; + Error *local_err = NULL; TestQtailq obj_q = { .i16 = -512, .i32 = 70000, @@ -773,7 +812,10 @@ static void test_load_q(void) TestQtailq tgt; QTAILQ_INIT(&tgt.q); - vmstate_load_state(fload, &vmstate_q, &tgt, 1); + ret = vmstate_load_state(fload, &vmstate_q, &tgt, 1, &local_err); + if (ret < 0) { + error_report_err(local_err); + } char eof = qemu_get_byte(fload); g_assert(!qemu_file_get_error(fload)); g_assert_cmpint(tgt.i16, ==, obj_q.i16); @@ -1115,6 +1157,8 @@ static void diff_iommu(TestGTreeIOMMU *iommu1, TestGTreeIOMMU *iommu2) static void test_gtree_load_domain(void) { + Error *local_err = NULL; + int ret; TestGTreeDomain *dest_domain = g_new0(TestGTreeDomain, 1); TestGTreeDomain *orig_domain = create_first_domain(); QEMUFile *fload, *fsave; @@ -1127,7 +1171,11 @@ static void test_gtree_load_domain(void) fload = open_test_file(false); - vmstate_load_state(fload, &vmstate_domain, dest_domain, 1); + ret = vmstate_load_state(fload, &vmstate_domain, dest_domain, 1, + &local_err); + if (ret < 0) { + error_report_err(local_err); + } eof = qemu_get_byte(fload); g_assert(!qemu_file_get_error(fload)); g_assert_cmpint(orig_domain->id, ==, dest_domain->id); @@ -1230,6 +1278,8 @@ static void test_gtree_save_iommu(void) static void test_gtree_load_iommu(void) { + Error *local_err = NULL; + int ret; TestGTreeIOMMU *dest_iommu = g_new0(TestGTreeIOMMU, 1); TestGTreeIOMMU *orig_iommu = create_iommu(); QEMUFile *fsave, *fload; @@ -1241,7 +1291,10 @@ static void test_gtree_load_iommu(void) qemu_fclose(fsave); fload = open_test_file(false); - vmstate_load_state(fload, &vmstate_iommu, dest_iommu, 1); + ret = vmstate_load_state(fload, &vmstate_iommu, dest_iommu, 1, &local_err); + if (ret < 0) { + error_report_err(local_err); + } eof = qemu_get_byte(fload); g_assert(!qemu_file_get_error(fload)); g_assert_cmpint(orig_iommu->id, ==, dest_iommu->id); @@ -1363,6 +1416,8 @@ static void test_save_qlist(void) static void test_load_qlist(void) { + Error *local_err = NULL; + int ret; QEMUFile *fsave, *fload; TestQListContainer *orig_container = alloc_container(); TestQListContainer *dest_container = g_new0(TestQListContainer, 1); @@ -1376,7 +1431,11 @@ static void test_load_qlist(void) qemu_fclose(fsave); fload = open_test_file(false); - vmstate_load_state(fload, &vmstate_container, dest_container, 1); + ret = vmstate_load_state(fload, &vmstate_container, dest_container, 1, + &local_err); + if (ret < 0) { + error_report_err(local_err); + } eof = qemu_get_byte(fload); g_assert(!qemu_file_get_error(fload)); g_assert_cmpint(eof, ==, QEMU_VM_EOF); |