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
);