]> Git Repo - qemu.git/blob - tests/test-vmstate.c
tests/qapi-schema: Cover union types with base
[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 int dup_temp_fd(bool truncate)
48 {
49     int fd = dup(temp_fd);
50     lseek(fd, 0, SEEK_SET);
51     if (truncate) {
52         g_assert_cmpint(ftruncate(fd, 0), ==, 0);
53     }
54     return fd;
55 }
56
57 typedef struct TestSruct {
58     uint32_t a, b, c, e;
59     uint64_t d, f;
60     bool skip_c_e;
61 } TestStruct;
62
63
64 static const VMStateDescription vmstate_simple = {
65     .name = "test",
66     .version_id = 1,
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),
74         VMSTATE_END_OF_LIST()
75     }
76 };
77
78 static void test_simple_save(void)
79 {
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));
84     qemu_fclose(fsave);
85
86     QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb");
87     uint8_t expected[] = {
88         0, 0, 0, 1, /* a */
89         0, 0, 0, 2, /* b */
90         0, 0, 0, 3, /* c */
91         0, 0, 0, 0, 0, 0, 0, 4, /* d */
92     };
93     uint8_t result[sizeof(expected)];
94     g_assert_cmpint(qemu_get_buffer(loading, result, sizeof(result)), ==,
95                     sizeof(result));
96     g_assert(!qemu_file_get_error(loading));
97     g_assert_cmpint(memcmp(result, expected, sizeof(result)), ==, 0);
98
99     /* Must reach EOF */
100     qemu_get_byte(loading);
101     g_assert_cmpint(qemu_file_get_error(loading), ==, -EIO);
102
103     qemu_fclose(loading);
104 }
105
106 static void test_simple_load(void)
107 {
108     QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb");
109     uint8_t buf[] = {
110         0, 0, 0, 10,             /* a */
111         0, 0, 0, 20,             /* b */
112         0, 0, 0, 30,             /* c */
113         0, 0, 0, 0, 0, 0, 0, 40, /* d */
114         QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
115     };
116     qemu_put_buffer(fsave, buf, sizeof(buf));
117     qemu_fclose(fsave);
118
119     QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb");
120     TestStruct obj;
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);
128 }
129
130 static const VMStateDescription vmstate_versioned = {
131     .name = "test",
132     .version_id = 2,
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.
139                                              */
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()
145     }
146 };
147
148 static void test_load_v1(void)
149 {
150     QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb");
151     uint8_t buf[] = {
152         0, 0, 0, 10,             /* a */
153         0, 0, 0, 30,             /* c */
154         0, 0, 0, 0, 0, 0, 0, 40, /* d */
155         QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
156     };
157     qemu_put_buffer(fsave, buf, sizeof(buf));
158     qemu_fclose(fsave);
159
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);
171 }
172
173 static void test_load_v2(void)
174 {
175     QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb");
176     uint8_t buf[] = {
177         0, 0, 0, 10,             /* a */
178         0, 0, 0, 20,             /* b */
179         0, 0, 0, 30,             /* c */
180         0, 0, 0, 0, 0, 0, 0, 40, /* d */
181         0, 0, 0, 50,             /* e */
182         0, 0, 0, 0, 0, 0, 0, 60, /* f */
183         QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
184     };
185     qemu_put_buffer(fsave, buf, sizeof(buf));
186     qemu_fclose(fsave);
187
188     QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb");
189     TestStruct obj;
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);
198 }
199
200 static bool test_skip(void *opaque, int version_id)
201 {
202     TestStruct *t = (TestStruct *)opaque;
203     return !t->skip_c_e;
204 }
205
206 static const VMStateDescription vmstate_skipping = {
207     .name = "test",
208     .version_id = 2,
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()
219     }
220 };
221
222
223 static void test_save_noskip(void)
224 {
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,
227                        .skip_c_e = false };
228     vmstate_save_state(fsave, &vmstate_skipping, &obj);
229     g_assert(!qemu_file_get_error(fsave));
230     qemu_fclose(fsave);
231
232     QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb");
233     uint8_t expected[] = {
234         0, 0, 0, 1,             /* a */
235         0, 0, 0, 2,             /* b */
236         0, 0, 0, 3,             /* c */
237         0, 0, 0, 0, 0, 0, 0, 4, /* d */
238         0, 0, 0, 5,             /* e */
239         0, 0, 0, 0, 0, 0, 0, 6, /* f */
240     };
241     uint8_t result[sizeof(expected)];
242     g_assert_cmpint(qemu_get_buffer(loading, result, sizeof(result)), ==,
243                     sizeof(result));
244     g_assert(!qemu_file_get_error(loading));
245     g_assert_cmpint(memcmp(result, expected, sizeof(result)), ==, 0);
246
247     /* Must reach EOF */
248     qemu_get_byte(loading);
249     g_assert_cmpint(qemu_file_get_error(loading), ==, -EIO);
250
251     qemu_fclose(loading);
252 }
253
254 static void test_save_skip(void)
255 {
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,
258                        .skip_c_e = true };
259     vmstate_save_state(fsave, &vmstate_skipping, &obj);
260     g_assert(!qemu_file_get_error(fsave));
261     qemu_fclose(fsave);
262
263     QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb");
264     uint8_t expected[] = {
265         0, 0, 0, 1,             /* a */
266         0, 0, 0, 2,             /* b */
267         0, 0, 0, 0, 0, 0, 0, 4, /* d */
268         0, 0, 0, 0, 0, 0, 0, 6, /* f */
269     };
270     uint8_t result[sizeof(expected)];
271     g_assert_cmpint(qemu_get_buffer(loading, result, sizeof(result)), ==,
272                     sizeof(result));
273     g_assert(!qemu_file_get_error(loading));
274     g_assert_cmpint(memcmp(result, expected, sizeof(result)), ==, 0);
275
276
277     /* Must reach EOF */
278     qemu_get_byte(loading);
279     g_assert_cmpint(qemu_file_get_error(loading), ==, -EIO);
280
281     qemu_fclose(loading);
282 }
283
284 static void test_load_noskip(void)
285 {
286     QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb");
287     uint8_t buf[] = {
288         0, 0, 0, 10,             /* a */
289         0, 0, 0, 20,             /* b */
290         0, 0, 0, 30,             /* c */
291         0, 0, 0, 0, 0, 0, 0, 40, /* d */
292         0, 0, 0, 50,             /* e */
293         0, 0, 0, 0, 0, 0, 0, 60, /* f */
294         QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
295     };
296     qemu_put_buffer(fsave, buf, sizeof(buf));
297     qemu_fclose(fsave);
298
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);
310 }
311
312 static void test_load_skip(void)
313 {
314     QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb");
315     uint8_t buf[] = {
316         0, 0, 0, 10,             /* a */
317         0, 0, 0, 20,             /* b */
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 */
321     };
322     qemu_put_buffer(fsave, buf, sizeof(buf));
323     qemu_fclose(fsave);
324
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);
336 }
337
338 int main(int argc, char **argv)
339 {
340     temp_fd = mkstemp(temp_file);
341
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);
351     g_test_run();
352
353     close(temp_fd);
354     unlink(temp_file);
355
356     return 0;
357 }
This page took 0.051561 seconds and 4 git commands to generate.