master
c 263 lines 7.61 KB
Raw
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(char *name, MigrateCommon *args)
26 {
27 QTestState *from, *to;
28
29 args->start.hide_stderr = true;
30
31 if (migrate_start(&from, &to, &args->start)) {
32 return;
33 }
34
35 migrate_incoming_qmp(to, "tcp:127.0.0.1:0", NULL, "{}");
36 migrate_qmp(from, to, "tcp:127.0.0.1:0", NULL, "{}");
37 wait_for_migration_fail(from, false);
38 migrate_end(from, to, false);
39 }
40
41 #ifndef _WIN32
42 static void test_analyze_script(char *name, MigrateCommon *args)
43 {
44 QTestState *from, *to;
45 g_autofree char *uri = NULL;
46 g_autofree char *file = NULL;
47 int pid, wstatus;
48 const char *python = g_getenv("PYTHON");
49
50 args->start.opts_source = "-uuid 11111111-1111-1111-1111-111111111111";
51
52 if (!python) {
53 g_test_skip("PYTHON variable not set");
54 return;
55 }
56
57 if (migrate_start(&from, &to, &args->start)) {
58 return;
59 }
60
61 /*
62 * Setting these two capabilities causes the "configuration"
63 * vmstate to include subsections for them. The script needs to
64 * parse those subsections properly.
65 */
66 migrate_set_capability(from, "validate-uuid", true);
67 migrate_set_capability(from, "x-ignore-shared", true);
68
69 file = g_strdup_printf("%s/migfile", tmpfs);
70 uri = g_strdup_printf("exec:cat > %s", file);
71
72 migrate_ensure_converge(from);
73 migrate_incoming_qmp(to, "tcp:127.0.0.1:0", NULL, "{}");
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 ignore_shared_assert_skipped(QTestState *from, QTestState *to,
96 void *data)
97 {
98 /* Check whether shared RAM has been really skipped */
99 g_assert_cmpint(
100 read_ram_property_int(from, "transferred"), <, 4 * 1024 * 1024);
101 }
102
103 static void test_ignore_shared(char *name, MigrateCommon *args)
104 {
105 args->live = true;
106 args->start.mem_type = MEM_TYPE_SHMEM;
107 args->start.caps[MIGRATION_CAPABILITY_X_IGNORE_SHARED] = true;
108 args->end_hook = ignore_shared_assert_skipped;
109
110 test_precopy_unix_common(args);
111 }
112
113 static void do_test_validate_uuid(MigrateStart *args, bool should_fail)
114 {
115 g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
116 QTestState *from, *to;
117
118 if (migrate_start(&from, &to, args)) {
119 return;
120 }
121
122 /*
123 * UUID validation is at the begin of migration. So, the main process of
124 * migration is not interesting for us here. Thus, set huge downtime for
125 * very fast migration.
126 */
127 migrate_set_parameter_int(from, "downtime-limit", 1000000);
128 migrate_set_capability(from, "validate-uuid", true);
129
130 /* Wait for the first serial output from the source */
131 wait_for_serial("src_serial");
132
133 migrate_incoming_qmp(to, uri, NULL, "{}");
134 migrate_qmp(from, to, uri, NULL, "{}");
135
136 if (should_fail) {
137 wait_for_migration_fail(from, true);
138 } else {
139 wait_for_migration_complete(from);
140 }
141
142 migrate_end(from, to, false);
143 }
144
145 static void test_validate_uuid(char *name, MigrateCommon *args)
146 {
147 args->start.opts_source = "-uuid 11111111-1111-1111-1111-111111111111";
148 args->start.opts_target = "-uuid 11111111-1111-1111-1111-111111111111";
149
150 do_test_validate_uuid(&args->start, false);
151 }
152
153 static void test_validate_uuid_error(char *name, MigrateCommon *args)
154 {
155 args->start.opts_source = "-uuid 11111111-1111-1111-1111-111111111111";
156 args->start.opts_target = "-uuid 22222222-2222-2222-2222-222222222222";
157 args->start.hide_stderr = true;
158
159 do_test_validate_uuid(&args->start, true);
160 }
161
162 static void test_validate_uuid_src_not_set(char *name, MigrateCommon *args)
163 {
164 args->start.opts_target = "-uuid 22222222-2222-2222-2222-222222222222";
165 args->start.hide_stderr = true;
166
167 do_test_validate_uuid(&args->start, false);
168 }
169
170 static void test_validate_uuid_dst_not_set(char *name, MigrateCommon *args)
171 {
172 args->start.opts_source = "-uuid 11111111-1111-1111-1111-111111111111";
173 args->start.hide_stderr = true;
174
175 do_test_validate_uuid(&args->start, false);
176 }
177
178 static void do_test_validate_uri_channel(MigrateCommon *args)
179 {
180 QTestState *from, *to;
181 QObject *channels;
182
183 if (migrate_start(&from, &to, &args->start)) {
184 return;
185 }
186
187 /* Wait for the first serial output from the source */
188 wait_for_serial("src_serial");
189
190 migrate_incoming_qmp(to, "tcp:127.0.0.1:0", NULL, "{}");
191
192 /*
193 * 'uri' and 'channels' validation is checked even before the migration
194 * starts.
195 */
196 channels = args->connect_channels ?
197 qobject_from_json(args->connect_channels, &error_abort) :
198 NULL;
199 migrate_qmp_fail(from, args->uri, channels, "{}");
200
201 migrate_end(from, to, false);
202 }
203
204 static void test_validate_uri_channels_both_set(char *name, MigrateCommon *args)
205 {
206 args->uri = "tcp:127.0.0.1:0",
207 args->connect_channels = ("[ { ""'channel-type': 'main',"
208 " 'addr': { 'transport': 'socket',"
209 " 'type': 'inet',"
210 " 'host': '127.0.0.1',"
211 " 'port': '0' } } ]"),
212
213 args->start.hide_stderr = true;
214
215 do_test_validate_uri_channel(args);
216 }
217
218 static void test_validate_uri_channels_none_set(char *name, MigrateCommon *args)
219 {
220 args->start.hide_stderr = true;
221
222 do_test_validate_uri_channel(args);
223 }
224
225 static void migration_test_add_misc_smoke(MigrationTestEnv *env)
226 {
227 #ifndef _WIN32
228 migration_test_add("/migration/analyze-script", test_analyze_script);
229 #endif
230 }
231
232 void migration_test_add_misc(MigrationTestEnv *env)
233 {
234 tmpfs = env->tmpfs;
235
236 migration_test_add_misc_smoke(env);
237
238 if (!env->full_set) {
239 return;
240 }
241
242 migration_test_add("/migration/bad_dest", test_baddest);
243
244 /*
245 * Our CI system has problems with shared memory.
246 * Don't run this test until we find a workaround.
247 */
248 if (getenv("QEMU_TEST_FLAKY_TESTS")) {
249 migration_test_add("/migration/ignore-shared", test_ignore_shared);
250 }
251
252 migration_test_add("/migration/validate_uuid", test_validate_uuid);
253 migration_test_add("/migration/validate_uuid_error",
254 test_validate_uuid_error);
255 migration_test_add("/migration/validate_uuid_src_not_set",
256 test_validate_uuid_src_not_set);
257 migration_test_add("/migration/validate_uuid_dst_not_set",
258 test_validate_uuid_dst_not_set);
259 migration_test_add("/migration/validate_uri/channels/both_set",
260 test_validate_uri_channels_both_set);
261 migration_test_add("/migration/validate_uri/channels/none_set",
262 test_validate_uri_channels_none_set);
263 }