qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

tests: add migration-helpers unit

Move a few helper functions from migration-test.c to migration-helpers.c

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>

+216 -166
+1 -1
tests/Makefile.include
··· 827 827 tests/usb-hcd-ehci-test$(EXESUF): tests/usb-hcd-ehci-test.o $(libqos-usb-obj-y) 828 828 tests/usb-hcd-xhci-test$(EXESUF): tests/usb-hcd-xhci-test.o $(libqos-usb-obj-y) 829 829 tests/cpu-plug-test$(EXESUF): tests/cpu-plug-test.o 830 - tests/migration-test$(EXESUF): tests/migration-test.o 830 + tests/migration-test$(EXESUF): tests/migration-test.o tests/migration-helpers.o 831 831 tests/qemu-iotests/socket_scm_helper$(EXESUF): tests/qemu-iotests/socket_scm_helper.o 832 832 tests/test-qemu-opts$(EXESUF): tests/test-qemu-opts.o $(test-util-obj-y) 833 833 tests/test-keyval$(EXESUF): tests/test-keyval.o $(test-util-obj-y) $(test-qapi-obj-y)
+167
tests/migration-helpers.c
··· 1 + /* 2 + * QTest migration helpers 3 + * 4 + * Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates 5 + * based on the vhost-user-test.c that is: 6 + * Copyright (c) 2014 Virtual Open Systems Sarl. 7 + * 8 + * This work is licensed under the terms of the GNU GPL, version 2 or later. 9 + * See the COPYING file in the top-level directory. 10 + * 11 + */ 12 + 13 + #include "qemu/osdep.h" 14 + #include "qapi/qmp/qjson.h" 15 + 16 + #include "migration-helpers.h" 17 + 18 + bool got_stop; 19 + 20 + static void stop_cb(void *opaque, const char *name, QDict *data) 21 + { 22 + if (!strcmp(name, "STOP")) { 23 + got_stop = true; 24 + } 25 + } 26 + 27 + /* 28 + * Events can get in the way of responses we are actually waiting for. 29 + */ 30 + QDict *wait_command_fd(QTestState *who, int fd, const char *command, ...) 31 + { 32 + va_list ap; 33 + 34 + va_start(ap, command); 35 + qtest_qmp_vsend_fds(who, &fd, 1, command, ap); 36 + va_end(ap); 37 + 38 + return qtest_qmp_receive_success(who, stop_cb, NULL); 39 + } 40 + 41 + /* 42 + * Events can get in the way of responses we are actually waiting for. 43 + */ 44 + QDict *wait_command(QTestState *who, const char *command, ...) 45 + { 46 + va_list ap; 47 + 48 + va_start(ap, command); 49 + qtest_qmp_vsend(who, command, ap); 50 + va_end(ap); 51 + 52 + return qtest_qmp_receive_success(who, stop_cb, NULL); 53 + } 54 + 55 + /* 56 + * Send QMP command "migrate". 57 + * Arguments are built from @fmt... (formatted like 58 + * qobject_from_jsonf_nofail()) with "uri": @uri spliced in. 59 + */ 60 + void migrate_qmp(QTestState *who, const char *uri, const char *fmt, ...) 61 + { 62 + va_list ap; 63 + QDict *args, *rsp; 64 + 65 + va_start(ap, fmt); 66 + args = qdict_from_vjsonf_nofail(fmt, ap); 67 + va_end(ap); 68 + 69 + g_assert(!qdict_haskey(args, "uri")); 70 + qdict_put_str(args, "uri", uri); 71 + 72 + rsp = qtest_qmp(who, "{ 'execute': 'migrate', 'arguments': %p}", args); 73 + 74 + g_assert(qdict_haskey(rsp, "return")); 75 + qobject_unref(rsp); 76 + } 77 + 78 + /* 79 + * Note: caller is responsible to free the returned object via 80 + * qobject_unref() after use 81 + */ 82 + QDict *migrate_query(QTestState *who) 83 + { 84 + return wait_command(who, "{ 'execute': 'query-migrate' }"); 85 + } 86 + 87 + /* 88 + * Note: caller is responsible to free the returned object via 89 + * g_free() after use 90 + */ 91 + static gchar *migrate_query_status(QTestState *who) 92 + { 93 + QDict *rsp_return = migrate_query(who); 94 + gchar *status = g_strdup(qdict_get_str(rsp_return, "status")); 95 + 96 + g_assert(status); 97 + qobject_unref(rsp_return); 98 + 99 + return status; 100 + } 101 + 102 + static bool check_migration_status(QTestState *who, const char *goal, 103 + const char **ungoals) 104 + { 105 + bool ready; 106 + char *current_status; 107 + const char **ungoal; 108 + 109 + current_status = migrate_query_status(who); 110 + ready = strcmp(current_status, goal) == 0; 111 + if (!ungoals) { 112 + g_assert_cmpstr(current_status, !=, "failed"); 113 + /* 114 + * If looking for a state other than completed, 115 + * completion of migration would cause the test to 116 + * hang. 117 + */ 118 + if (strcmp(goal, "completed") != 0) { 119 + g_assert_cmpstr(current_status, !=, "completed"); 120 + } 121 + } else { 122 + for (ungoal = ungoals; *ungoal; ungoal++) { 123 + g_assert_cmpstr(current_status, !=, *ungoal); 124 + } 125 + } 126 + g_free(current_status); 127 + return ready; 128 + } 129 + 130 + void wait_for_migration_status(QTestState *who, 131 + const char *goal, const char **ungoals) 132 + { 133 + while (!check_migration_status(who, goal, ungoals)) { 134 + usleep(1000); 135 + } 136 + } 137 + 138 + void wait_for_migration_complete(QTestState *who) 139 + { 140 + wait_for_migration_status(who, "completed", NULL); 141 + } 142 + 143 + void wait_for_migration_fail(QTestState *from, bool allow_active) 144 + { 145 + QDict *rsp_return; 146 + char *status; 147 + bool failed; 148 + 149 + do { 150 + status = migrate_query_status(from); 151 + bool result = !strcmp(status, "setup") || !strcmp(status, "failed") || 152 + (allow_active && !strcmp(status, "active")); 153 + if (!result) { 154 + fprintf(stderr, "%s: unexpected status status=%s allow_active=%d\n", 155 + __func__, status, allow_active); 156 + } 157 + g_assert(result); 158 + failed = !strcmp(status, "failed"); 159 + g_free(status); 160 + } while (!failed); 161 + 162 + /* Is the machine currently running? */ 163 + rsp_return = wait_command(from, "{ 'execute': 'query-status' }"); 164 + g_assert(qdict_haskey(rsp_return, "running")); 165 + g_assert(qdict_get_bool(rsp_return, "running")); 166 + qobject_unref(rsp_return); 167 + }
+37
tests/migration-helpers.h
··· 1 + /* 2 + * QTest migration helpers 3 + * 4 + * Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates 5 + * based on the vhost-user-test.c that is: 6 + * Copyright (c) 2014 Virtual Open Systems Sarl. 7 + * 8 + * This work is licensed under the terms of the GNU GPL, version 2 or later. 9 + * See the COPYING file in the top-level directory. 10 + * 11 + */ 12 + #ifndef MIGRATION_HELPERS_H_ 13 + #define MIGRATION_HELPERS_H_ 14 + 15 + #include "libqtest.h" 16 + 17 + extern bool got_stop; 18 + 19 + GCC_FMT_ATTR(3, 4) 20 + QDict *wait_command_fd(QTestState *who, int fd, const char *command, ...); 21 + 22 + GCC_FMT_ATTR(2, 3) 23 + QDict *wait_command(QTestState *who, const char *command, ...); 24 + 25 + GCC_FMT_ATTR(3, 4) 26 + void migrate_qmp(QTestState *who, const char *uri, const char *fmt, ...); 27 + 28 + QDict *migrate_query(QTestState *who); 29 + 30 + void wait_for_migration_status(QTestState *who, 31 + const char *goal, const char **ungoals); 32 + 33 + void wait_for_migration_complete(QTestState *who); 34 + 35 + void wait_for_migration_fail(QTestState *from, bool allow_active); 36 + 37 + #endif /* MIGRATION_HELPERS_H_ */
+11 -165
tests/migration-test.c
··· 14 14 15 15 #include "libqtest.h" 16 16 #include "qapi/qmp/qdict.h" 17 - #include "qapi/qmp/qjson.h" 18 17 #include "qemu/module.h" 19 18 #include "qemu/option.h" 20 19 #include "qemu/range.h" ··· 24 23 #include "qapi/qobject-input-visitor.h" 25 24 #include "qapi/qobject-output-visitor.h" 26 25 26 + #include "migration-helpers.h" 27 27 #include "migration/migration-test.h" 28 28 29 29 /* TODO actually test the results and get rid of this */ ··· 31 31 32 32 unsigned start_address; 33 33 unsigned end_address; 34 - bool got_stop; 35 34 static bool uffd_feature_thread_id; 36 35 37 36 #if defined(__linux__) ··· 157 156 } while (true); 158 157 } 159 158 160 - static void stop_cb(void *opaque, const char *name, QDict *data) 161 - { 162 - if (!strcmp(name, "STOP")) { 163 - got_stop = true; 164 - } 165 - } 166 - 167 - /* 168 - * Events can get in the way of responses we are actually waiting for. 169 - */ 170 - GCC_FMT_ATTR(3, 4) 171 - static QDict *wait_command_fd(QTestState *who, int fd, const char *command, ...) 172 - { 173 - va_list ap; 174 - 175 - va_start(ap, command); 176 - qtest_qmp_vsend_fds(who, &fd, 1, command, ap); 177 - va_end(ap); 178 - 179 - return qtest_qmp_receive_success(who, stop_cb, NULL); 180 - } 181 - 182 - /* 183 - * Events can get in the way of responses we are actually waiting for. 184 - */ 185 - GCC_FMT_ATTR(2, 3) 186 - static QDict *wait_command(QTestState *who, const char *command, ...) 187 - { 188 - va_list ap; 189 - 190 - va_start(ap, command); 191 - qtest_qmp_vsend(who, command, ap); 192 - va_end(ap); 193 - 194 - return qtest_qmp_receive_success(who, stop_cb, NULL); 195 - } 196 - 197 - /* 198 - * Note: caller is responsible to free the returned object via 199 - * qobject_unref() after use 200 - */ 201 - static QDict *migrate_query(QTestState *who) 202 - { 203 - return wait_command(who, "{ 'execute': 'query-migrate' }"); 204 - } 205 - 206 - /* 207 - * Note: caller is responsible to free the returned object via 208 - * g_free() after use 209 - */ 210 - static gchar *migrate_query_status(QTestState *who) 211 - { 212 - QDict *rsp_return = migrate_query(who); 213 - gchar *status = g_strdup(qdict_get_str(rsp_return, "status")); 214 - 215 - g_assert(status); 216 - qobject_unref(rsp_return); 217 - 218 - return status; 219 - } 220 - 221 159 /* 222 160 * It's tricky to use qemu's migration event capability with qtest, 223 161 * events suddenly appearing confuse the qmp()/hmp() responses. ··· 265 203 qobject_unref(rsp_return); 266 204 } 267 205 268 - static bool check_migration_status(QTestState *who, const char *goal, 269 - const char **ungoals) 270 - { 271 - bool ready; 272 - char *current_status; 273 - const char **ungoal; 274 - 275 - current_status = migrate_query_status(who); 276 - ready = strcmp(current_status, goal) == 0; 277 - if (!ungoals) { 278 - g_assert_cmpstr(current_status, !=, "failed"); 279 - /* 280 - * If looking for a state other than completed, 281 - * completion of migration would cause the test to 282 - * hang. 283 - */ 284 - if (strcmp(goal, "completed") != 0) { 285 - g_assert_cmpstr(current_status, !=, "completed"); 286 - } 287 - } else { 288 - for (ungoal = ungoals; *ungoal; ungoal++) { 289 - g_assert_cmpstr(current_status, !=, *ungoal); 290 - } 291 - } 292 - g_free(current_status); 293 - return ready; 294 - } 295 - 296 - static void wait_for_migration_status(QTestState *who, 297 - const char *goal, 298 - const char **ungoals) 299 - { 300 - while (!check_migration_status(who, goal, ungoals)) { 301 - usleep(1000); 302 - } 303 - } 304 - 305 - static void wait_for_migration_complete(QTestState *who) 306 - { 307 - wait_for_migration_status(who, "completed", NULL); 308 - } 309 - 310 206 static void wait_for_migration_pass(QTestState *who) 311 207 { 312 208 uint64_t initial_pass = get_migration_pass(who); ··· 502 398 "'capabilities': [ { " 503 399 "'capability': %s, 'state': %i } ] } }", 504 400 capability, value); 505 - g_assert(qdict_haskey(rsp, "return")); 506 - qobject_unref(rsp); 507 - } 508 - 509 - /* 510 - * Send QMP command "migrate". 511 - * Arguments are built from @fmt... (formatted like 512 - * qobject_from_jsonf_nofail()) with "uri": @uri spliced in. 513 - */ 514 - GCC_FMT_ATTR(3, 4) 515 - static void migrate(QTestState *who, const char *uri, const char *fmt, ...) 516 - { 517 - va_list ap; 518 - QDict *args, *rsp; 519 - 520 - va_start(ap, fmt); 521 - args = qdict_from_vjsonf_nofail(fmt, ap); 522 - va_end(ap); 523 - 524 - g_assert(!qdict_haskey(args, "uri")); 525 - qdict_put_str(args, "uri", uri); 526 - 527 - rsp = qtest_qmp(who, "{ 'execute': 'migrate', 'arguments': %p}", args); 528 - 529 401 g_assert(qdict_haskey(rsp, "return")); 530 402 qobject_unref(rsp); 531 403 } ··· 800 672 /* Wait for the first serial output from the source */ 801 673 wait_for_serial("src_serial"); 802 674 803 - migrate(from, uri, "{}"); 675 + migrate_qmp(from, uri, "{}"); 804 676 g_free(uri); 805 677 806 678 wait_for_migration_pass(from); ··· 891 763 wait_for_migration_status(from, "postcopy-paused", 892 764 (const char * []) { "failed", "active", 893 765 "completed", NULL }); 894 - migrate(from, uri, "{'resume': true}"); 766 + migrate_qmp(from, uri, "{'resume': true}"); 895 767 g_free(uri); 896 768 897 769 /* Restore the postcopy bandwidth to unlimited */ ··· 900 772 migrate_postcopy_complete(from, to); 901 773 } 902 774 903 - static void wait_for_migration_fail(QTestState *from, bool allow_active) 904 - { 905 - QDict *rsp_return; 906 - char *status; 907 - bool failed; 908 - 909 - do { 910 - status = migrate_query_status(from); 911 - bool result = !strcmp(status, "setup") || !strcmp(status, "failed") || 912 - (allow_active && !strcmp(status, "active")); 913 - if (!result) { 914 - fprintf(stderr, "%s: unexpected status status=%s allow_active=%d\n", 915 - __func__, status, allow_active); 916 - } 917 - g_assert(result); 918 - failed = !strcmp(status, "failed"); 919 - g_free(status); 920 - } while (!failed); 921 - 922 - /* Is the machine currently running? */ 923 - rsp_return = wait_command(from, "{ 'execute': 'query-status' }"); 924 - g_assert(qdict_haskey(rsp_return, "running")); 925 - g_assert(qdict_get_bool(rsp_return, "running")); 926 - qobject_unref(rsp_return); 927 - } 928 - 929 775 static void test_baddest(void) 930 776 { 931 777 MigrateStart *args = migrate_start_new(); ··· 936 782 if (test_migrate_start(&from, &to, "tcp:0:0", args)) { 937 783 return; 938 784 } 939 - migrate(from, "tcp:0:0", "{}"); 785 + migrate_qmp(from, "tcp:0:0", "{}"); 940 786 wait_for_migration_fail(from, false); 941 787 test_migrate_end(from, to, false); 942 788 } ··· 963 809 /* Wait for the first serial output from the source */ 964 810 wait_for_serial("src_serial"); 965 811 966 - migrate(from, uri, "{}"); 812 + migrate_qmp(from, uri, "{}"); 967 813 968 814 wait_for_migration_pass(from); 969 815 ··· 1000 846 /* Wait for the first serial output from the source */ 1001 847 wait_for_serial("src_serial"); 1002 848 1003 - migrate(from, uri, "{}"); 849 + migrate_qmp(from, uri, "{}"); 1004 850 1005 851 wait_for_migration_pass(from); 1006 852 ··· 1047 893 /* Wait for the first serial output from the source */ 1048 894 wait_for_serial("src_serial"); 1049 895 1050 - migrate(from, uri, "{}"); 896 + migrate_qmp(from, uri, "{}"); 1051 897 1052 898 wait_for_migration_pass(from); 1053 899 ··· 1098 944 1099 945 uri = migrate_get_socket_address(to, "socket-address"); 1100 946 1101 - migrate(from, uri, "{}"); 947 + migrate_qmp(from, uri, "{}"); 1102 948 1103 949 wait_for_migration_pass(from); 1104 950 ··· 1167 1013 close(pair[1]); 1168 1014 1169 1015 /* Start migration to the 2nd socket*/ 1170 - migrate(from, "fd:fd-mig", "{}"); 1016 + migrate_qmp(from, "fd:fd-mig", "{}"); 1171 1017 1172 1018 wait_for_migration_pass(from); 1173 1019 ··· 1222 1068 /* Wait for the first serial output from the source */ 1223 1069 wait_for_serial("src_serial"); 1224 1070 1225 - migrate(from, uri, "{}"); 1071 + migrate_qmp(from, uri, "{}"); 1226 1072 1227 1073 if (should_fail) { 1228 1074 qtest_set_expected_status(to, 1); ··· 1316 1162 /* Wait for the first serial output from the source */ 1317 1163 wait_for_serial("src_serial"); 1318 1164 1319 - migrate(from, uri, "{}"); 1165 + migrate_qmp(from, uri, "{}"); 1320 1166 1321 1167 /* Wait for throttling begins */ 1322 1168 percentage = 0;