2 * Test code for VMState
4 * Copyright (c) 2013 Red Hat Inc.
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 #include "qemu-common.h"
28 #include "migration/migration.h"
29 #include "migration/vmstate.h"
30 #include "block/coroutine.h"
32 char temp_file[] = "/tmp/vmst.test.XXXXXX";
35 /* Fake yield_until_fd_readable() implementation so we don't have to pull the
36 * coroutine code as dependency.
38 void yield_until_fd_readable(int fd)
43 select(fd + 1, &fds, NULL, NULL, NULL);
46 /* Duplicate temp_fd and seek to the beginning of the file */
47 static int dup_temp_fd(bool truncate)
49 int fd = dup(temp_fd);
50 lseek(fd, 0, SEEK_SET);
52 g_assert_cmpint(ftruncate(fd, 0), ==, 0);
57 typedef struct TestSruct {
64 static const VMStateDescription vmstate_simple = {
67 .minimum_version_id = 1,
68 .minimum_version_id_old = 1,
69 .fields = (VMStateField[]) {
70 VMSTATE_UINT32(a, TestStruct),
71 VMSTATE_UINT32(b, TestStruct),
72 VMSTATE_UINT32(c, TestStruct),
73 VMSTATE_UINT64(d, TestStruct),
78 static void test_simple_save(void)
80 QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb");
81 TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4 };
82 vmstate_save_state(fsave, &vmstate_simple, &obj);
83 g_assert(!qemu_file_get_error(fsave));
86 QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb");
87 uint8_t expected[] = {
91 0, 0, 0, 0, 0, 0, 0, 4, /* d */
93 uint8_t result[sizeof(expected)];
94 g_assert_cmpint(qemu_get_buffer(loading, result, sizeof(result)), ==,
96 g_assert(!qemu_file_get_error(loading));
97 g_assert_cmpint(memcmp(result, expected, sizeof(result)), ==, 0);
100 qemu_get_byte(loading);
101 g_assert_cmpint(qemu_file_get_error(loading), ==, -EIO);
103 qemu_fclose(loading);
106 static void test_simple_load(void)
108 QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb");
113 0, 0, 0, 0, 0, 0, 0, 40, /* d */
114 QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
116 qemu_put_buffer(fsave, buf, sizeof(buf));
119 QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb");
121 vmstate_load_state(loading, &vmstate_simple, &obj, 1);
122 g_assert(!qemu_file_get_error(loading));
123 g_assert_cmpint(obj.a, ==, 10);
124 g_assert_cmpint(obj.b, ==, 20);
125 g_assert_cmpint(obj.c, ==, 30);
126 g_assert_cmpint(obj.d, ==, 40);
127 qemu_fclose(loading);
130 static const VMStateDescription vmstate_versioned = {
133 .minimum_version_id = 1,
134 .minimum_version_id_old = 1,
135 .fields = (VMStateField []) {
136 VMSTATE_UINT32(a, TestStruct),
137 VMSTATE_UINT32_V(b, TestStruct, 2), /* Versioned field in the middle, so
138 * we catch bugs more easily.
140 VMSTATE_UINT32(c, TestStruct),
141 VMSTATE_UINT64(d, TestStruct),
142 VMSTATE_UINT32_V(e, TestStruct, 2),
143 VMSTATE_UINT64_V(f, TestStruct, 2),
144 VMSTATE_END_OF_LIST()
148 static void test_load_v1(void)
150 QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb");
154 0, 0, 0, 0, 0, 0, 0, 40, /* d */
155 QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
157 qemu_put_buffer(fsave, buf, sizeof(buf));
160 QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb");
161 TestStruct obj = { .b = 200, .e = 500, .f = 600 };
162 vmstate_load_state(loading, &vmstate_versioned, &obj, 1);
163 g_assert(!qemu_file_get_error(loading));
164 g_assert_cmpint(obj.a, ==, 10);
165 g_assert_cmpint(obj.b, ==, 200);
166 g_assert_cmpint(obj.c, ==, 30);
167 g_assert_cmpint(obj.d, ==, 40);
168 g_assert_cmpint(obj.e, ==, 500);
169 g_assert_cmpint(obj.f, ==, 600);
170 qemu_fclose(loading);
173 static void test_load_v2(void)
175 QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb");
180 0, 0, 0, 0, 0, 0, 0, 40, /* d */
182 0, 0, 0, 0, 0, 0, 0, 60, /* f */
183 QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
185 qemu_put_buffer(fsave, buf, sizeof(buf));
188 QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb");
190 vmstate_load_state(loading, &vmstate_versioned, &obj, 2);
191 g_assert_cmpint(obj.a, ==, 10);
192 g_assert_cmpint(obj.b, ==, 20);
193 g_assert_cmpint(obj.c, ==, 30);
194 g_assert_cmpint(obj.d, ==, 40);
195 g_assert_cmpint(obj.e, ==, 50);
196 g_assert_cmpint(obj.f, ==, 60);
197 qemu_fclose(loading);
200 static bool test_skip(void *opaque, int version_id)
202 TestStruct *t = (TestStruct *)opaque;
206 static const VMStateDescription vmstate_skipping = {
209 .minimum_version_id = 1,
210 .minimum_version_id_old = 1,
211 .fields = (VMStateField []) {
212 VMSTATE_UINT32(a, TestStruct),
213 VMSTATE_UINT32(b, TestStruct),
214 VMSTATE_UINT32_TEST(c, TestStruct, test_skip),
215 VMSTATE_UINT64(d, TestStruct),
216 VMSTATE_UINT32_TEST(e, TestStruct, test_skip),
217 VMSTATE_UINT64_V(f, TestStruct, 2),
218 VMSTATE_END_OF_LIST()
223 static void test_save_noskip(void)
225 QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb");
226 TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4, .e = 5, .f = 6,
228 vmstate_save_state(fsave, &vmstate_skipping, &obj);
229 g_assert(!qemu_file_get_error(fsave));
232 QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb");
233 uint8_t expected[] = {
237 0, 0, 0, 0, 0, 0, 0, 4, /* d */
239 0, 0, 0, 0, 0, 0, 0, 6, /* f */
241 uint8_t result[sizeof(expected)];
242 g_assert_cmpint(qemu_get_buffer(loading, result, sizeof(result)), ==,
244 g_assert(!qemu_file_get_error(loading));
245 g_assert_cmpint(memcmp(result, expected, sizeof(result)), ==, 0);
248 qemu_get_byte(loading);
249 g_assert_cmpint(qemu_file_get_error(loading), ==, -EIO);
251 qemu_fclose(loading);
254 static void test_save_skip(void)
256 QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb");
257 TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4, .e = 5, .f = 6,
259 vmstate_save_state(fsave, &vmstate_skipping, &obj);
260 g_assert(!qemu_file_get_error(fsave));
263 QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb");
264 uint8_t expected[] = {
267 0, 0, 0, 0, 0, 0, 0, 4, /* d */
268 0, 0, 0, 0, 0, 0, 0, 6, /* f */
270 uint8_t result[sizeof(expected)];
271 g_assert_cmpint(qemu_get_buffer(loading, result, sizeof(result)), ==,
273 g_assert(!qemu_file_get_error(loading));
274 g_assert_cmpint(memcmp(result, expected, sizeof(result)), ==, 0);
278 qemu_get_byte(loading);
279 g_assert_cmpint(qemu_file_get_error(loading), ==, -EIO);
281 qemu_fclose(loading);
284 static void test_load_noskip(void)
286 QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb");
291 0, 0, 0, 0, 0, 0, 0, 40, /* d */
293 0, 0, 0, 0, 0, 0, 0, 60, /* f */
294 QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
296 qemu_put_buffer(fsave, buf, sizeof(buf));
299 QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb");
300 TestStruct obj = { .skip_c_e = false };
301 vmstate_load_state(loading, &vmstate_skipping, &obj, 2);
302 g_assert(!qemu_file_get_error(loading));
303 g_assert_cmpint(obj.a, ==, 10);
304 g_assert_cmpint(obj.b, ==, 20);
305 g_assert_cmpint(obj.c, ==, 30);
306 g_assert_cmpint(obj.d, ==, 40);
307 g_assert_cmpint(obj.e, ==, 50);
308 g_assert_cmpint(obj.f, ==, 60);
309 qemu_fclose(loading);
312 static void test_load_skip(void)
314 QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb");
318 0, 0, 0, 0, 0, 0, 0, 40, /* d */
319 0, 0, 0, 0, 0, 0, 0, 60, /* f */
320 QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
322 qemu_put_buffer(fsave, buf, sizeof(buf));
325 QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb");
326 TestStruct obj = { .skip_c_e = true, .c = 300, .e = 500 };
327 vmstate_load_state(loading, &vmstate_skipping, &obj, 2);
328 g_assert(!qemu_file_get_error(loading));
329 g_assert_cmpint(obj.a, ==, 10);
330 g_assert_cmpint(obj.b, ==, 20);
331 g_assert_cmpint(obj.c, ==, 300);
332 g_assert_cmpint(obj.d, ==, 40);
333 g_assert_cmpint(obj.e, ==, 500);
334 g_assert_cmpint(obj.f, ==, 60);
335 qemu_fclose(loading);
338 int main(int argc, char **argv)
340 temp_fd = mkstemp(temp_file);
342 g_test_init(&argc, &argv, NULL);
343 g_test_add_func("/vmstate/simple/save", test_simple_save);
344 g_test_add_func("/vmstate/simple/load", test_simple_load);
345 g_test_add_func("/vmstate/versioned/load/v1", test_load_v1);
346 g_test_add_func("/vmstate/versioned/load/v2", test_load_v2);
347 g_test_add_func("/vmstate/field_exists/load/noskip", test_load_noskip);
348 g_test_add_func("/vmstate/field_exists/load/skip", test_load_skip);
349 g_test_add_func("/vmstate/field_exists/save/noskip", test_save_noskip);
350 g_test_add_func("/vmstate/field_exists/save/skip", test_save_skip);