MAINTAINERS: mark megasas as maintained
[qemu/ar7.git] / tests / test-vmstate.c
blob75cd1a1fd4126eab543c3576297e07d8d86aef51
1 /*
2 * Test code for VMState
4 * Copyright (c) 2013 Red Hat Inc.
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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.
25 #include <glib.h>
27 #include "qemu-common.h"
28 #include "migration/migration.h"
29 #include "migration/vmstate.h"
30 #include "block/coroutine.h"
32 char temp_file[] = "/tmp/vmst.test.XXXXXX";
33 int temp_fd;
35 /* Fake yield_until_fd_readable() implementation so we don't have to pull the
36 * coroutine code as dependency.
38 void yield_until_fd_readable(int fd)
40 fd_set fds;
41 FD_ZERO(&fds);
42 FD_SET(fd, &fds);
43 select(fd + 1, &fds, NULL, NULL, NULL);
46 /* Duplicate temp_fd and seek to the beginning of the file */
47 static int dup_temp_fd(bool truncate)
49 int fd = dup(temp_fd);
50 lseek(fd, 0, SEEK_SET);
51 if (truncate) {
52 g_assert_cmpint(ftruncate(fd, 0), ==, 0);
54 return fd;
57 typedef struct TestSruct {
58 uint32_t a, b, c, e;
59 uint64_t d, f;
60 bool skip_c_e;
61 } TestStruct;
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()
78 static void test_simple_save(void)
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);
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 */
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);
99 /* Must reach EOF */
100 qemu_get_byte(loading);
101 g_assert_cmpint(qemu_file_get_error(loading), ==, -EIO);
103 qemu_fclose(loading);
106 static void test_simple_load(void)
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 */
116 qemu_put_buffer(fsave, buf, sizeof(buf));
117 qemu_fclose(fsave);
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);
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.
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()
148 static void test_load_v1(void)
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 */
157 qemu_put_buffer(fsave, buf, sizeof(buf));
158 qemu_fclose(fsave);
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);
173 static void test_load_v2(void)
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 */
185 qemu_put_buffer(fsave, buf, sizeof(buf));
186 qemu_fclose(fsave);
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);
200 static bool test_skip(void *opaque, int version_id)
202 TestStruct *t = (TestStruct *)opaque;
203 return !t->skip_c_e;
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()
223 static void test_save_noskip(void)
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);
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 */
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);
247 /* Must reach EOF */
248 qemu_get_byte(loading);
249 g_assert_cmpint(qemu_file_get_error(loading), ==, -EIO);
251 qemu_fclose(loading);
254 static void test_save_skip(void)
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);
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 */
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);
277 /* Must reach EOF */
278 qemu_get_byte(loading);
279 g_assert_cmpint(qemu_file_get_error(loading), ==, -EIO);
281 qemu_fclose(loading);
284 static void test_load_noskip(void)
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 */
296 qemu_put_buffer(fsave, buf, sizeof(buf));
297 qemu_fclose(fsave);
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);
312 static void test_load_skip(void)
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 */
322 qemu_put_buffer(fsave, buf, sizeof(buf));
323 qemu_fclose(fsave);
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);
338 int main(int argc, char **argv)
340 temp_fd = mkstemp(temp_file);
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();
353 close(temp_fd);
354 unlink(temp_file);
356 return 0;