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