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