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