]> git.proxmox.com Git - mirror_qemu.git/blob - tests/test-vmstate.c
Merge remote-tracking branch 'remotes/stefanha/tags/block-pull-request' into staging
[mirror_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 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 .fields = (VMStateField[]) {
69 VMSTATE_UINT32(a, TestStruct),
70 VMSTATE_UINT32(b, TestStruct),
71 VMSTATE_UINT32(c, TestStruct),
72 VMSTATE_UINT64(d, TestStruct),
73 VMSTATE_END_OF_LIST()
74 }
75 };
76
77 static void test_simple_save(void)
78 {
79 QEMUFile *fsave = open_test_file(true);
80 TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4 };
81 vmstate_save_state(fsave, &vmstate_simple, &obj);
82 g_assert(!qemu_file_get_error(fsave));
83 qemu_fclose(fsave);
84
85 QEMUFile *loading = open_test_file(false);
86 uint8_t expected[] = {
87 0, 0, 0, 1, /* a */
88 0, 0, 0, 2, /* b */
89 0, 0, 0, 3, /* c */
90 0, 0, 0, 0, 0, 0, 0, 4, /* d */
91 };
92 uint8_t result[sizeof(expected)];
93 g_assert_cmpint(qemu_get_buffer(loading, result, sizeof(result)), ==,
94 sizeof(result));
95 g_assert(!qemu_file_get_error(loading));
96 g_assert_cmpint(memcmp(result, expected, sizeof(result)), ==, 0);
97
98 /* Must reach EOF */
99 qemu_get_byte(loading);
100 g_assert_cmpint(qemu_file_get_error(loading), ==, -EIO);
101
102 qemu_fclose(loading);
103 }
104
105 static void test_simple_load(void)
106 {
107 QEMUFile *fsave = open_test_file(true);
108 uint8_t buf[] = {
109 0, 0, 0, 10, /* a */
110 0, 0, 0, 20, /* b */
111 0, 0, 0, 30, /* c */
112 0, 0, 0, 0, 0, 0, 0, 40, /* d */
113 QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
114 };
115 qemu_put_buffer(fsave, buf, sizeof(buf));
116 qemu_fclose(fsave);
117
118 QEMUFile *loading = open_test_file(false);
119 TestStruct obj;
120 vmstate_load_state(loading, &vmstate_simple, &obj, 1);
121 g_assert(!qemu_file_get_error(loading));
122 g_assert_cmpint(obj.a, ==, 10);
123 g_assert_cmpint(obj.b, ==, 20);
124 g_assert_cmpint(obj.c, ==, 30);
125 g_assert_cmpint(obj.d, ==, 40);
126 qemu_fclose(loading);
127 }
128
129 static const VMStateDescription vmstate_versioned = {
130 .name = "test",
131 .version_id = 2,
132 .minimum_version_id = 1,
133 .fields = (VMStateField[]) {
134 VMSTATE_UINT32(a, TestStruct),
135 VMSTATE_UINT32_V(b, TestStruct, 2), /* Versioned field in the middle, so
136 * we catch bugs more easily.
137 */
138 VMSTATE_UINT32(c, TestStruct),
139 VMSTATE_UINT64(d, TestStruct),
140 VMSTATE_UINT32_V(e, TestStruct, 2),
141 VMSTATE_UINT64_V(f, TestStruct, 2),
142 VMSTATE_END_OF_LIST()
143 }
144 };
145
146 static void test_load_v1(void)
147 {
148 QEMUFile *fsave = open_test_file(true);
149 uint8_t buf[] = {
150 0, 0, 0, 10, /* a */
151 0, 0, 0, 30, /* c */
152 0, 0, 0, 0, 0, 0, 0, 40, /* d */
153 QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
154 };
155 qemu_put_buffer(fsave, buf, sizeof(buf));
156 qemu_fclose(fsave);
157
158 QEMUFile *loading = open_test_file(false);
159 TestStruct obj = { .b = 200, .e = 500, .f = 600 };
160 vmstate_load_state(loading, &vmstate_versioned, &obj, 1);
161 g_assert(!qemu_file_get_error(loading));
162 g_assert_cmpint(obj.a, ==, 10);
163 g_assert_cmpint(obj.b, ==, 200);
164 g_assert_cmpint(obj.c, ==, 30);
165 g_assert_cmpint(obj.d, ==, 40);
166 g_assert_cmpint(obj.e, ==, 500);
167 g_assert_cmpint(obj.f, ==, 600);
168 qemu_fclose(loading);
169 }
170
171 static void test_load_v2(void)
172 {
173 QEMUFile *fsave = open_test_file(true);
174 uint8_t buf[] = {
175 0, 0, 0, 10, /* a */
176 0, 0, 0, 20, /* b */
177 0, 0, 0, 30, /* c */
178 0, 0, 0, 0, 0, 0, 0, 40, /* d */
179 0, 0, 0, 50, /* e */
180 0, 0, 0, 0, 0, 0, 0, 60, /* f */
181 QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
182 };
183 qemu_put_buffer(fsave, buf, sizeof(buf));
184 qemu_fclose(fsave);
185
186 QEMUFile *loading = open_test_file(false);
187 TestStruct obj;
188 vmstate_load_state(loading, &vmstate_versioned, &obj, 2);
189 g_assert_cmpint(obj.a, ==, 10);
190 g_assert_cmpint(obj.b, ==, 20);
191 g_assert_cmpint(obj.c, ==, 30);
192 g_assert_cmpint(obj.d, ==, 40);
193 g_assert_cmpint(obj.e, ==, 50);
194 g_assert_cmpint(obj.f, ==, 60);
195 qemu_fclose(loading);
196 }
197
198 static bool test_skip(void *opaque, int version_id)
199 {
200 TestStruct *t = (TestStruct *)opaque;
201 return !t->skip_c_e;
202 }
203
204 static const VMStateDescription vmstate_skipping = {
205 .name = "test",
206 .version_id = 2,
207 .minimum_version_id = 1,
208 .fields = (VMStateField[]) {
209 VMSTATE_UINT32(a, TestStruct),
210 VMSTATE_UINT32(b, TestStruct),
211 VMSTATE_UINT32_TEST(c, TestStruct, test_skip),
212 VMSTATE_UINT64(d, TestStruct),
213 VMSTATE_UINT32_TEST(e, TestStruct, test_skip),
214 VMSTATE_UINT64_V(f, TestStruct, 2),
215 VMSTATE_END_OF_LIST()
216 }
217 };
218
219
220 static void test_save_noskip(void)
221 {
222 QEMUFile *fsave = open_test_file(true);
223 TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4, .e = 5, .f = 6,
224 .skip_c_e = false };
225 vmstate_save_state(fsave, &vmstate_skipping, &obj);
226 g_assert(!qemu_file_get_error(fsave));
227 qemu_fclose(fsave);
228
229 QEMUFile *loading = open_test_file(false);
230 uint8_t expected[] = {
231 0, 0, 0, 1, /* a */
232 0, 0, 0, 2, /* b */
233 0, 0, 0, 3, /* c */
234 0, 0, 0, 0, 0, 0, 0, 4, /* d */
235 0, 0, 0, 5, /* e */
236 0, 0, 0, 0, 0, 0, 0, 6, /* f */
237 };
238 uint8_t result[sizeof(expected)];
239 g_assert_cmpint(qemu_get_buffer(loading, result, sizeof(result)), ==,
240 sizeof(result));
241 g_assert(!qemu_file_get_error(loading));
242 g_assert_cmpint(memcmp(result, expected, sizeof(result)), ==, 0);
243
244 /* Must reach EOF */
245 qemu_get_byte(loading);
246 g_assert_cmpint(qemu_file_get_error(loading), ==, -EIO);
247
248 qemu_fclose(loading);
249 }
250
251 static void test_save_skip(void)
252 {
253 QEMUFile *fsave = open_test_file(true);
254 TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4, .e = 5, .f = 6,
255 .skip_c_e = true };
256 vmstate_save_state(fsave, &vmstate_skipping, &obj);
257 g_assert(!qemu_file_get_error(fsave));
258 qemu_fclose(fsave);
259
260 QEMUFile *loading = open_test_file(false);
261 uint8_t expected[] = {
262 0, 0, 0, 1, /* a */
263 0, 0, 0, 2, /* b */
264 0, 0, 0, 0, 0, 0, 0, 4, /* d */
265 0, 0, 0, 0, 0, 0, 0, 6, /* f */
266 };
267 uint8_t result[sizeof(expected)];
268 g_assert_cmpint(qemu_get_buffer(loading, result, sizeof(result)), ==,
269 sizeof(result));
270 g_assert(!qemu_file_get_error(loading));
271 g_assert_cmpint(memcmp(result, expected, sizeof(result)), ==, 0);
272
273
274 /* Must reach EOF */
275 qemu_get_byte(loading);
276 g_assert_cmpint(qemu_file_get_error(loading), ==, -EIO);
277
278 qemu_fclose(loading);
279 }
280
281 static void test_load_noskip(void)
282 {
283 QEMUFile *fsave = open_test_file(true);
284 uint8_t buf[] = {
285 0, 0, 0, 10, /* a */
286 0, 0, 0, 20, /* b */
287 0, 0, 0, 30, /* c */
288 0, 0, 0, 0, 0, 0, 0, 40, /* d */
289 0, 0, 0, 50, /* e */
290 0, 0, 0, 0, 0, 0, 0, 60, /* f */
291 QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
292 };
293 qemu_put_buffer(fsave, buf, sizeof(buf));
294 qemu_fclose(fsave);
295
296 QEMUFile *loading = open_test_file(false);
297 TestStruct obj = { .skip_c_e = false };
298 vmstate_load_state(loading, &vmstate_skipping, &obj, 2);
299 g_assert(!qemu_file_get_error(loading));
300 g_assert_cmpint(obj.a, ==, 10);
301 g_assert_cmpint(obj.b, ==, 20);
302 g_assert_cmpint(obj.c, ==, 30);
303 g_assert_cmpint(obj.d, ==, 40);
304 g_assert_cmpint(obj.e, ==, 50);
305 g_assert_cmpint(obj.f, ==, 60);
306 qemu_fclose(loading);
307 }
308
309 static void test_load_skip(void)
310 {
311 QEMUFile *fsave = open_test_file(true);
312 uint8_t buf[] = {
313 0, 0, 0, 10, /* a */
314 0, 0, 0, 20, /* b */
315 0, 0, 0, 0, 0, 0, 0, 40, /* d */
316 0, 0, 0, 0, 0, 0, 0, 60, /* f */
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 = { .skip_c_e = true, .c = 300, .e = 500 };
324 vmstate_load_state(loading, &vmstate_skipping, &obj, 2);
325 g_assert(!qemu_file_get_error(loading));
326 g_assert_cmpint(obj.a, ==, 10);
327 g_assert_cmpint(obj.b, ==, 20);
328 g_assert_cmpint(obj.c, ==, 300);
329 g_assert_cmpint(obj.d, ==, 40);
330 g_assert_cmpint(obj.e, ==, 500);
331 g_assert_cmpint(obj.f, ==, 60);
332 qemu_fclose(loading);
333 }
334
335 int main(int argc, char **argv)
336 {
337 temp_fd = mkstemp(temp_file);
338
339 g_test_init(&argc, &argv, NULL);
340 g_test_add_func("/vmstate/simple/save", test_simple_save);
341 g_test_add_func("/vmstate/simple/load", test_simple_load);
342 g_test_add_func("/vmstate/versioned/load/v1", test_load_v1);
343 g_test_add_func("/vmstate/versioned/load/v2", test_load_v2);
344 g_test_add_func("/vmstate/field_exists/load/noskip", test_load_noskip);
345 g_test_add_func("/vmstate/field_exists/load/skip", test_load_skip);
346 g_test_add_func("/vmstate/field_exists/save/noskip", test_save_noskip);
347 g_test_add_func("/vmstate/field_exists/save/skip", test_save_skip);
348 g_test_run();
349
350 close(temp_fd);
351 unlink(temp_file);
352
353 return 0;
354 }