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