1 /*
2 * QTest testcases for migration
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/error.h"
15 #include "qobject/qjson.h"
16 #include "libqtest.h"
17 #include "migration/framework.h"
18 #include "migration/migration-qmp.h"
19 #include "migration/migration-util.h"
20
21 #define ANALYZE_SCRIPT "scripts/analyze-migration.py"
22
23 static char *tmpfs;
24
test_baddest(void)25 static void test_baddest(void)
26 {
27 MigrateStart args = {
28 .hide_stderr = true
29 };
30 QTestState *from, *to;
31
32 if (migrate_start(&from, &to, "tcp:127.0.0.1:0", &args)) {
33 return;
34 }
35 migrate_qmp(from, to, "tcp:127.0.0.1:0", NULL, "{}");
36 wait_for_migration_fail(from, false);
37 migrate_end(from, to, false);
38 }
39
40 #ifndef _WIN32
test_analyze_script(void)41 static void test_analyze_script(void)
42 {
43 MigrateStart args = {
44 .opts_source = "-uuid 11111111-1111-1111-1111-111111111111",
45 };
46 QTestState *from, *to;
47 g_autofree char *uri = NULL;
48 g_autofree char *file = NULL;
49 int pid, wstatus;
50 const char *python = g_getenv("PYTHON");
51
52 if (!python) {
53 g_test_skip("PYTHON variable not set");
54 return;
55 }
56
57 /* dummy url */
58 if (migrate_start(&from, &to, "tcp:127.0.0.1:0", &args)) {
59 return;
60 }
61
62 /*
63 * Setting these two capabilities causes the "configuration"
64 * vmstate to include subsections for them. The script needs to
65 * parse those subsections properly.
66 */
67 migrate_set_capability(from, "validate-uuid", true);
68 migrate_set_capability(from, "x-ignore-shared", true);
69
70 file = g_strdup_printf("%s/migfile", tmpfs);
71 uri = g_strdup_printf("exec:cat > %s", file);
72
73 migrate_ensure_converge(from);
74 migrate_qmp(from, to, uri, NULL, "{}");
75 wait_for_migration_complete(from);
76
77 pid = fork();
78 if (!pid) {
79 close(1);
80 open("/dev/null", O_WRONLY);
81 execl(python, python, ANALYZE_SCRIPT, "-f", file, NULL);
82 g_assert_not_reached();
83 }
84
85 g_assert(waitpid(pid, &wstatus, 0) == pid);
86 if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus) != 0) {
87 g_test_message("Failed to analyze the migration stream");
88 g_test_fail();
89 }
90 migrate_end(from, to, false);
91 unlink(file);
92 }
93 #endif
94
test_ignore_shared(void)95 static void test_ignore_shared(void)
96 {
97 g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
98 QTestState *from, *to;
99 MigrateStart args = {
100 .use_shmem = true,
101 };
102
103 if (migrate_start(&from, &to, uri, &args)) {
104 return;
105 }
106
107 migrate_ensure_non_converge(from);
108 migrate_prepare_for_dirty_mem(from);
109
110 migrate_set_capability(from, "x-ignore-shared", true);
111 migrate_set_capability(to, "x-ignore-shared", true);
112
113 /* Wait for the first serial output from the source */
114 wait_for_serial("src_serial");
115
116 migrate_qmp(from, to, uri, NULL, "{}");
117
118 migrate_wait_for_dirty_mem(from, to);
119
120 wait_for_stop(from, get_src());
121
122 qtest_qmp_eventwait(to, "RESUME");
123
124 wait_for_serial("dest_serial");
125 wait_for_migration_complete(from);
126
127 /* Check whether shared RAM has been really skipped */
128 g_assert_cmpint(
129 read_ram_property_int(from, "transferred"), <, 4 * 1024 * 1024);
130
131 migrate_end(from, to, true);
132 }
133
do_test_validate_uuid(MigrateStart * args,bool should_fail)134 static void do_test_validate_uuid(MigrateStart *args, bool should_fail)
135 {
136 g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
137 QTestState *from, *to;
138
139 if (migrate_start(&from, &to, uri, args)) {
140 return;
141 }
142
143 /*
144 * UUID validation is at the begin of migration. So, the main process of
145 * migration is not interesting for us here. Thus, set huge downtime for
146 * very fast migration.
147 */
148 migrate_set_parameter_int(from, "downtime-limit", 1000000);
149 migrate_set_capability(from, "validate-uuid", true);
150
151 /* Wait for the first serial output from the source */
152 wait_for_serial("src_serial");
153
154 migrate_qmp(from, to, uri, NULL, "{}");
155
156 if (should_fail) {
157 qtest_set_expected_status(to, EXIT_FAILURE);
158 wait_for_migration_fail(from, true);
159 } else {
160 wait_for_migration_complete(from);
161 }
162
163 migrate_end(from, to, false);
164 }
165
test_validate_uuid(void)166 static void test_validate_uuid(void)
167 {
168 MigrateStart args = {
169 .opts_source = "-uuid 11111111-1111-1111-1111-111111111111",
170 .opts_target = "-uuid 11111111-1111-1111-1111-111111111111",
171 };
172
173 do_test_validate_uuid(&args, false);
174 }
175
test_validate_uuid_error(void)176 static void test_validate_uuid_error(void)
177 {
178 MigrateStart args = {
179 .opts_source = "-uuid 11111111-1111-1111-1111-111111111111",
180 .opts_target = "-uuid 22222222-2222-2222-2222-222222222222",
181 .hide_stderr = true,
182 };
183
184 do_test_validate_uuid(&args, true);
185 }
186
test_validate_uuid_src_not_set(void)187 static void test_validate_uuid_src_not_set(void)
188 {
189 MigrateStart args = {
190 .opts_target = "-uuid 22222222-2222-2222-2222-222222222222",
191 .hide_stderr = true,
192 };
193
194 do_test_validate_uuid(&args, false);
195 }
196
test_validate_uuid_dst_not_set(void)197 static void test_validate_uuid_dst_not_set(void)
198 {
199 MigrateStart args = {
200 .opts_source = "-uuid 11111111-1111-1111-1111-111111111111",
201 .hide_stderr = true,
202 };
203
204 do_test_validate_uuid(&args, false);
205 }
206
do_test_validate_uri_channel(MigrateCommon * args)207 static void do_test_validate_uri_channel(MigrateCommon *args)
208 {
209 QTestState *from, *to;
210 QObject *channels;
211
212 if (migrate_start(&from, &to, args->listen_uri, &args->start)) {
213 return;
214 }
215
216 /* Wait for the first serial output from the source */
217 wait_for_serial("src_serial");
218
219 /*
220 * 'uri' and 'channels' validation is checked even before the migration
221 * starts.
222 */
223 channels = args->connect_channels ?
224 qobject_from_json(args->connect_channels, &error_abort) :
225 NULL;
226 migrate_qmp_fail(from, args->connect_uri, channels, "{}");
227
228 migrate_end(from, to, false);
229 }
230
test_validate_uri_channels_both_set(void)231 static void test_validate_uri_channels_both_set(void)
232 {
233 MigrateCommon args = {
234 .start = {
235 .hide_stderr = true,
236 },
237 .listen_uri = "defer",
238 .connect_uri = "tcp:127.0.0.1:0",
239 .connect_channels = ("[ { ""'channel-type': 'main',"
240 " 'addr': { 'transport': 'socket',"
241 " 'type': 'inet',"
242 " 'host': '127.0.0.1',"
243 " 'port': '0' } } ]"),
244 };
245
246 do_test_validate_uri_channel(&args);
247 }
248
test_validate_uri_channels_none_set(void)249 static void test_validate_uri_channels_none_set(void)
250 {
251 MigrateCommon args = {
252 .start = {
253 .hide_stderr = true,
254 },
255 .listen_uri = "defer",
256 };
257
258 do_test_validate_uri_channel(&args);
259 }
260
migration_test_add_misc_smoke(MigrationTestEnv * env)261 static void migration_test_add_misc_smoke(MigrationTestEnv *env)
262 {
263 #ifndef _WIN32
264 migration_test_add("/migration/analyze-script", test_analyze_script);
265 #endif
266 }
267
migration_test_add_misc(MigrationTestEnv * env)268 void migration_test_add_misc(MigrationTestEnv *env)
269 {
270 tmpfs = env->tmpfs;
271
272 migration_test_add_misc_smoke(env);
273
274 if (!env->full_set) {
275 return;
276 }
277
278 migration_test_add("/migration/bad_dest", test_baddest);
279
280 /*
281 * Our CI system has problems with shared memory.
282 * Don't run this test until we find a workaround.
283 */
284 if (getenv("QEMU_TEST_FLAKY_TESTS")) {
285 migration_test_add("/migration/ignore-shared", test_ignore_shared);
286 }
287
288 migration_test_add("/migration/validate_uuid", test_validate_uuid);
289 migration_test_add("/migration/validate_uuid_error",
290 test_validate_uuid_error);
291 migration_test_add("/migration/validate_uuid_src_not_set",
292 test_validate_uuid_src_not_set);
293 migration_test_add("/migration/validate_uuid_dst_not_set",
294 test_validate_uuid_dst_not_set);
295 migration_test_add("/migration/validate_uri/channels/both_set",
296 test_validate_uri_channels_both_set);
297 migration_test_add("/migration/validate_uri/channels/none_set",
298 test_validate_uri_channels_none_set);
299 }
300