xref: /qemu/tests/qtest/migration/misc-tests.c (revision f07a5674cf97b8473e5d06d7b1df9b51e97d553f)
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 
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
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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