]> Git Repo - qemu.git/blob - tests/test-vmstate.c
Merge remote-tracking branch 'remotes/bonzini/memory' into staging
[qemu.git] / tests / test-vmstate.c
1 /*
2  *  Test code for VMState
3  *
4  *  Copyright (c) 2013 Red Hat Inc.
5  *
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:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
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
22  * THE SOFTWARE.
23  */
24
25 #include <glib.h>
26
27 #include "qemu-common.h"
28 #include "migration/migration.h"
29 #include "migration/vmstate.h"
30 #include "block/coroutine.h"
31
32 char temp_file[] = "/tmp/vmst.test.XXXXXX";
33 int temp_fd;
34
35 /* Fake yield_until_fd_readable() implementation so we don't have to pull the
36  * coroutine code as dependency.
37  */
38 void yield_until_fd_readable(int fd)
39 {
40     fd_set fds;
41     FD_ZERO(&fds);
42     FD_SET(fd, &fds);
43     select(fd + 1, &fds, NULL, NULL, NULL);
44 }
45
46 /* Duplicate temp_fd and seek to the beginning of the file */
47 static QEMUFile *open_test_file(bool write)
48 {
49     int fd = dup(temp_fd);
50     lseek(fd, 0, SEEK_SET);
51     if (write) {
52         g_assert_cmpint(ftruncate(fd, 0), ==, 0);
53     }
54     return qemu_fdopen(fd, write ? "wb" : "rb");
55 }
56
57 #define SUCCESS(val) \
58     g_assert_cmpint((val), ==, 0)
59
60 #define FAILURE(val) \
61     g_assert_cmpint((val), !=, 0)
62
63 static void save_vmstate(const VMStateDescription *desc, void *obj)
64 {
65     QEMUFile *f = open_test_file(true);
66
67     /* Save file with vmstate */
68     vmstate_save_state(f, desc, obj);
69     qemu_put_byte(f, QEMU_VM_EOF);
70     g_assert(!qemu_file_get_error(f));
71     qemu_fclose(f);
72 }
73
74 static void compare_vmstate(uint8_t *wire, size_t size)
75 {
76     QEMUFile *f = open_test_file(false);
77     uint8_t result[size];
78
79     /* read back as binary */
80
81     g_assert_cmpint(qemu_get_buffer(f, result, sizeof(result)), ==,
82                     sizeof(result));
83     g_assert(!qemu_file_get_error(f));
84
85     /* Compare that what is on the file is the same that what we
86        expected to be there */
87     SUCCESS(memcmp(result, wire, sizeof(result)));
88
89     /* Must reach EOF */
90     qemu_get_byte(f);
91     g_assert_cmpint(qemu_file_get_error(f), ==, -EIO);
92
93     qemu_fclose(f);
94 }
95
96 static int load_vmstate_one(const VMStateDescription *desc, void *obj,
97                             int version, uint8_t *wire, size_t size)
98 {
99     QEMUFile *f;
100     int ret;
101
102     f = open_test_file(true);
103     qemu_put_buffer(f, wire, size);
104     qemu_fclose(f);
105
106     f = open_test_file(false);
107     ret = vmstate_load_state(f, desc, obj, version);
108     if (ret) {
109         g_assert(qemu_file_get_error(f));
110     } else{
111         g_assert(!qemu_file_get_error(f));
112     }
113     qemu_fclose(f);
114     return ret;
115 }
116
117
118 static int load_vmstate(const VMStateDescription *desc,
119                         void *obj, void *obj_clone,
120                         void (*obj_copy)(void *, void*),
121                         int version, uint8_t *wire, size_t size)
122 {
123     /* We test with zero size */
124     obj_copy(obj_clone, obj);
125     FAILURE(load_vmstate_one(desc, obj, version, wire, 0));
126
127     /* Stream ends with QEMU_EOF, so we need at least 3 bytes to be
128      * able to test in the middle */
129
130     if (size > 3) {
131
132         /* We test with size - 2. We can't test size - 1 due to EOF tricks */
133         obj_copy(obj, obj_clone);
134         FAILURE(load_vmstate_one(desc, obj, version, wire, size - 2));
135
136         /* Test with size/2, first half of real state */
137         obj_copy(obj, obj_clone);
138         FAILURE(load_vmstate_one(desc, obj, version, wire, size/2));
139
140         /* Test with size/2, second half of real state */
141         obj_copy(obj, obj_clone);
142         FAILURE(load_vmstate_one(desc, obj, version, wire + (size/2), size/2));
143
144     }
145     obj_copy(obj, obj_clone);
146     return load_vmstate_one(desc, obj, version, wire, size);
147 }
148
149 /* Test struct that we are going to use for our tests */
150
151 typedef struct TestSimple {
152     bool     b_1,   b_2;
153     uint8_t  u8_1;
154     uint16_t u16_1;
155     uint32_t u32_1;
156     uint64_t u64_1;
157     int8_t   i8_1,  i8_2;
158     int16_t  i16_1, i16_2;
159     int32_t  i32_1, i32_2;
160     int64_t  i64_1, i64_2;
161 } TestSimple;
162
163 /* Object instantiation, we are going to use it in more than one test */
164
165 TestSimple obj_simple = {
166     .b_1 = true,
167     .b_2 = false,
168     .u8_1 = 130,
169     .u16_1 = 512,
170     .u32_1 = 70000,
171     .u64_1 = 12121212,
172     .i8_1 = 65,
173     .i8_2 = -65,
174     .i16_1 = 512,
175     .i16_2 = -512,
176     .i32_1 = 70000,
177     .i32_2 = -70000,
178     .i64_1 = 12121212,
179     .i64_2 = -12121212,
180 };
181
182 /* Description of the values.  If you add a primitive type
183    you are expected to add a test here */
184
185 static const VMStateDescription vmstate_simple_primitive = {
186     .name = "simple/primitive",
187     .version_id = 1,
188     .minimum_version_id = 1,
189     .fields = (VMStateField[]) {
190         VMSTATE_BOOL(b_1, TestSimple),
191         VMSTATE_BOOL(b_2, TestSimple),
192         VMSTATE_UINT8(u8_1, TestSimple),
193         VMSTATE_UINT16(u16_1, TestSimple),
194         VMSTATE_UINT32(u32_1, TestSimple),
195         VMSTATE_UINT64(u64_1, TestSimple),
196         VMSTATE_INT8(i8_1, TestSimple),
197         VMSTATE_INT8(i8_2, TestSimple),
198         VMSTATE_INT16(i16_1, TestSimple),
199         VMSTATE_INT16(i16_2, TestSimple),
200         VMSTATE_INT32(i32_1, TestSimple),
201         VMSTATE_INT32(i32_2, TestSimple),
202         VMSTATE_INT64(i64_1, TestSimple),
203         VMSTATE_INT64(i64_2, TestSimple),
204         VMSTATE_END_OF_LIST()
205     }
206 };
207
208 /* It describes what goes through the wire.  Our tests are basically:
209
210    * save test
211      - save a struct a vmstate to a file
212      - read that file back (binary read, no vmstate)
213      - compare it with what we expect to be on the wire
214    * load test
215      - save to the file what we expect to be on the wire
216      - read struct back with vmstate in a different
217      - compare back with the original struct
218 */
219
220 uint8_t wire_simple_primitive[] = {
221     /* b_1 */   0x01,
222     /* b_2 */   0x00,
223     /* u8_1 */  0x82,
224     /* u16_1 */ 0x02, 0x00,
225     /* u32_1 */ 0x00, 0x01, 0x11, 0x70,
226     /* u64_1 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xf4, 0x7c,
227     /* i8_1 */  0x41,
228     /* i8_2 */  0xbf,
229     /* i16_1 */ 0x02, 0x00,
230     /* i16_2 */ 0xfe, 0x0,
231     /* i32_1 */ 0x00, 0x01, 0x11, 0x70,
232     /* i32_2 */ 0xff, 0xfe, 0xee, 0x90,
233     /* i64_1 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xf4, 0x7c,
234     /* i64_2 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0x47, 0x0b, 0x84,
235     QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
236 };
237
238 static void obj_simple_copy(void *target, void *source)
239 {
240     memcpy(target, source, sizeof(TestSimple));
241 }
242
243 static void test_simple_primitive(void)
244 {
245     TestSimple obj, obj_clone;
246
247     memset(&obj, 0, sizeof(obj));
248     save_vmstate(&vmstate_simple_primitive, &obj_simple);
249
250     compare_vmstate(wire_simple_primitive, sizeof(wire_simple_primitive));
251
252     SUCCESS(load_vmstate(&vmstate_simple_primitive, &obj, &obj_clone,
253                          obj_simple_copy, 1, wire_simple_primitive,
254                          sizeof(wire_simple_primitive)));
255
256 #define FIELD_EQUAL(name)   g_assert_cmpint(obj.name, ==, obj_simple.name)
257
258     FIELD_EQUAL(b_1);
259     FIELD_EQUAL(b_2);
260     FIELD_EQUAL(u8_1);
261     FIELD_EQUAL(u16_1);
262     FIELD_EQUAL(u32_1);
263     FIELD_EQUAL(u64_1);
264     FIELD_EQUAL(i8_1);
265     FIELD_EQUAL(i8_2);
266     FIELD_EQUAL(i16_1);
267     FIELD_EQUAL(i16_2);
268     FIELD_EQUAL(i32_1);
269     FIELD_EQUAL(i32_2);
270     FIELD_EQUAL(i64_1);
271     FIELD_EQUAL(i64_2);
272 }
273 #undef FIELD_EQUAL
274
275 typedef struct TestStruct {
276     uint32_t a, b, c, e;
277     uint64_t d, f;
278     bool skip_c_e;
279 } TestStruct;
280
281 static const VMStateDescription vmstate_versioned = {
282     .name = "test/versioned",
283     .version_id = 2,
284     .minimum_version_id = 1,
285     .fields = (VMStateField[]) {
286         VMSTATE_UINT32(a, TestStruct),
287         VMSTATE_UINT32_V(b, TestStruct, 2), /* Versioned field in the middle, so
288                                              * we catch bugs more easily.
289                                              */
290         VMSTATE_UINT32(c, TestStruct),
291         VMSTATE_UINT64(d, TestStruct),
292         VMSTATE_UINT32_V(e, TestStruct, 2),
293         VMSTATE_UINT64_V(f, TestStruct, 2),
294         VMSTATE_END_OF_LIST()
295     }
296 };
297
298 static void test_load_v1(void)
299 {
300     QEMUFile *fsave = open_test_file(true);
301     uint8_t buf[] = {
302         0, 0, 0, 10,             /* a */
303         0, 0, 0, 30,             /* c */
304         0, 0, 0, 0, 0, 0, 0, 40, /* d */
305         QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
306     };
307     qemu_put_buffer(fsave, buf, sizeof(buf));
308     qemu_fclose(fsave);
309
310     QEMUFile *loading = open_test_file(false);
311     TestStruct obj = { .b = 200, .e = 500, .f = 600 };
312     vmstate_load_state(loading, &vmstate_versioned, &obj, 1);
313     g_assert(!qemu_file_get_error(loading));
314     g_assert_cmpint(obj.a, ==, 10);
315     g_assert_cmpint(obj.b, ==, 200);
316     g_assert_cmpint(obj.c, ==, 30);
317     g_assert_cmpint(obj.d, ==, 40);
318     g_assert_cmpint(obj.e, ==, 500);
319     g_assert_cmpint(obj.f, ==, 600);
320     qemu_fclose(loading);
321 }
322
323 static void test_load_v2(void)
324 {
325     QEMUFile *fsave = open_test_file(true);
326     uint8_t buf[] = {
327         0, 0, 0, 10,             /* a */
328         0, 0, 0, 20,             /* b */
329         0, 0, 0, 30,             /* c */
330         0, 0, 0, 0, 0, 0, 0, 40, /* d */
331         0, 0, 0, 50,             /* e */
332         0, 0, 0, 0, 0, 0, 0, 60, /* f */
333         QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
334     };
335     qemu_put_buffer(fsave, buf, sizeof(buf));
336     qemu_fclose(fsave);
337
338     QEMUFile *loading = open_test_file(false);
339     TestStruct obj;
340     vmstate_load_state(loading, &vmstate_versioned, &obj, 2);
341     g_assert_cmpint(obj.a, ==, 10);
342     g_assert_cmpint(obj.b, ==, 20);
343     g_assert_cmpint(obj.c, ==, 30);
344     g_assert_cmpint(obj.d, ==, 40);
345     g_assert_cmpint(obj.e, ==, 50);
346     g_assert_cmpint(obj.f, ==, 60);
347     qemu_fclose(loading);
348 }
349
350 static bool test_skip(void *opaque, int version_id)
351 {
352     TestStruct *t = (TestStruct *)opaque;
353     return !t->skip_c_e;
354 }
355
356 static const VMStateDescription vmstate_skipping = {
357     .name = "test/skip",
358     .version_id = 2,
359     .minimum_version_id = 1,
360     .fields = (VMStateField[]) {
361         VMSTATE_UINT32(a, TestStruct),
362         VMSTATE_UINT32(b, TestStruct),
363         VMSTATE_UINT32_TEST(c, TestStruct, test_skip),
364         VMSTATE_UINT64(d, TestStruct),
365         VMSTATE_UINT32_TEST(e, TestStruct, test_skip),
366         VMSTATE_UINT64_V(f, TestStruct, 2),
367         VMSTATE_END_OF_LIST()
368     }
369 };
370
371
372 static void test_save_noskip(void)
373 {
374     QEMUFile *fsave = open_test_file(true);
375     TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4, .e = 5, .f = 6,
376                        .skip_c_e = false };
377     vmstate_save_state(fsave, &vmstate_skipping, &obj);
378     g_assert(!qemu_file_get_error(fsave));
379     qemu_fclose(fsave);
380
381     QEMUFile *loading = open_test_file(false);
382     uint8_t expected[] = {
383         0, 0, 0, 1,             /* a */
384         0, 0, 0, 2,             /* b */
385         0, 0, 0, 3,             /* c */
386         0, 0, 0, 0, 0, 0, 0, 4, /* d */
387         0, 0, 0, 5,             /* e */
388         0, 0, 0, 0, 0, 0, 0, 6, /* f */
389     };
390     uint8_t result[sizeof(expected)];
391     g_assert_cmpint(qemu_get_buffer(loading, result, sizeof(result)), ==,
392                     sizeof(result));
393     g_assert(!qemu_file_get_error(loading));
394     g_assert_cmpint(memcmp(result, expected, sizeof(result)), ==, 0);
395
396     /* Must reach EOF */
397     qemu_get_byte(loading);
398     g_assert_cmpint(qemu_file_get_error(loading), ==, -EIO);
399
400     qemu_fclose(loading);
401 }
402
403 static void test_save_skip(void)
404 {
405     QEMUFile *fsave = open_test_file(true);
406     TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4, .e = 5, .f = 6,
407                        .skip_c_e = true };
408     vmstate_save_state(fsave, &vmstate_skipping, &obj);
409     g_assert(!qemu_file_get_error(fsave));
410     qemu_fclose(fsave);
411
412     QEMUFile *loading = open_test_file(false);
413     uint8_t expected[] = {
414         0, 0, 0, 1,             /* a */
415         0, 0, 0, 2,             /* b */
416         0, 0, 0, 0, 0, 0, 0, 4, /* d */
417         0, 0, 0, 0, 0, 0, 0, 6, /* f */
418     };
419     uint8_t result[sizeof(expected)];
420     g_assert_cmpint(qemu_get_buffer(loading, result, sizeof(result)), ==,
421                     sizeof(result));
422     g_assert(!qemu_file_get_error(loading));
423     g_assert_cmpint(memcmp(result, expected, sizeof(result)), ==, 0);
424
425
426     /* Must reach EOF */
427     qemu_get_byte(loading);
428     g_assert_cmpint(qemu_file_get_error(loading), ==, -EIO);
429
430     qemu_fclose(loading);
431 }
432
433 static void test_load_noskip(void)
434 {
435     QEMUFile *fsave = open_test_file(true);
436     uint8_t buf[] = {
437         0, 0, 0, 10,             /* a */
438         0, 0, 0, 20,             /* b */
439         0, 0, 0, 30,             /* c */
440         0, 0, 0, 0, 0, 0, 0, 40, /* d */
441         0, 0, 0, 50,             /* e */
442         0, 0, 0, 0, 0, 0, 0, 60, /* f */
443         QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
444     };
445     qemu_put_buffer(fsave, buf, sizeof(buf));
446     qemu_fclose(fsave);
447
448     QEMUFile *loading = open_test_file(false);
449     TestStruct obj = { .skip_c_e = false };
450     vmstate_load_state(loading, &vmstate_skipping, &obj, 2);
451     g_assert(!qemu_file_get_error(loading));
452     g_assert_cmpint(obj.a, ==, 10);
453     g_assert_cmpint(obj.b, ==, 20);
454     g_assert_cmpint(obj.c, ==, 30);
455     g_assert_cmpint(obj.d, ==, 40);
456     g_assert_cmpint(obj.e, ==, 50);
457     g_assert_cmpint(obj.f, ==, 60);
458     qemu_fclose(loading);
459 }
460
461 static void test_load_skip(void)
462 {
463     QEMUFile *fsave = open_test_file(true);
464     uint8_t buf[] = {
465         0, 0, 0, 10,             /* a */
466         0, 0, 0, 20,             /* b */
467         0, 0, 0, 0, 0, 0, 0, 40, /* d */
468         0, 0, 0, 0, 0, 0, 0, 60, /* f */
469         QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
470     };
471     qemu_put_buffer(fsave, buf, sizeof(buf));
472     qemu_fclose(fsave);
473
474     QEMUFile *loading = open_test_file(false);
475     TestStruct obj = { .skip_c_e = true, .c = 300, .e = 500 };
476     vmstate_load_state(loading, &vmstate_skipping, &obj, 2);
477     g_assert(!qemu_file_get_error(loading));
478     g_assert_cmpint(obj.a, ==, 10);
479     g_assert_cmpint(obj.b, ==, 20);
480     g_assert_cmpint(obj.c, ==, 300);
481     g_assert_cmpint(obj.d, ==, 40);
482     g_assert_cmpint(obj.e, ==, 500);
483     g_assert_cmpint(obj.f, ==, 60);
484     qemu_fclose(loading);
485 }
486
487 int main(int argc, char **argv)
488 {
489     temp_fd = mkstemp(temp_file);
490
491     g_test_init(&argc, &argv, NULL);
492     g_test_add_func("/vmstate/simple/primitive", test_simple_primitive);
493     g_test_add_func("/vmstate/versioned/load/v1", test_load_v1);
494     g_test_add_func("/vmstate/versioned/load/v2", test_load_v2);
495     g_test_add_func("/vmstate/field_exists/load/noskip", test_load_noskip);
496     g_test_add_func("/vmstate/field_exists/load/skip", test_load_skip);
497     g_test_add_func("/vmstate/field_exists/save/noskip", test_save_noskip);
498     g_test_add_func("/vmstate/field_exists/save/skip", test_save_skip);
499     g_test_run();
500
501     close(temp_fd);
502     unlink(temp_file);
503
504     return 0;
505 }
This page took 0.050631 seconds and 4 git commands to generate.