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
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";
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
)
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
);
52 g_assert_cmpint(ftruncate(fd
, 0), ==, 0);
57 typedef struct TestSruct
{
64 static const VMStateDescription vmstate_simple
= {
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
),
77 static void test_simple_save(void)
79 QEMUFile
*fsave
= qemu_fdopen(dup_temp_fd(true), "wb");
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
));
85 QEMUFile
*loading
= qemu_fdopen(dup_temp_fd(false), "rb");
86 uint8_t expected
[] = {
90 0, 0, 0, 0, 0, 0, 0, 4, /* d */
92 uint8_t result
[sizeof(expected
)];
93 g_assert_cmpint(qemu_get_buffer(loading
, result
, sizeof(result
)), ==,
95 g_assert(!qemu_file_get_error(loading
));
96 g_assert_cmpint(memcmp(result
, expected
, sizeof(result
)), ==, 0);
99 qemu_get_byte(loading
);
100 g_assert_cmpint(qemu_file_get_error(loading
), ==, -EIO
);
102 qemu_fclose(loading
);
105 static void test_simple_load(void)
107 QEMUFile
*fsave
= qemu_fdopen(dup_temp_fd(true), "wb");
112 0, 0, 0, 0, 0, 0, 0, 40, /* d */
113 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
115 qemu_put_buffer(fsave
, buf
, sizeof(buf
));
118 QEMUFile
*loading
= qemu_fdopen(dup_temp_fd(false), "rb");
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
);
129 static const VMStateDescription vmstate_versioned
= {
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.
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()
146 static void test_load_v1(void)
148 QEMUFile
*fsave
= qemu_fdopen(dup_temp_fd(true), "wb");
152 0, 0, 0, 0, 0, 0, 0, 40, /* d */
153 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
155 qemu_put_buffer(fsave
, buf
, sizeof(buf
));
158 QEMUFile
*loading
= qemu_fdopen(dup_temp_fd(false), "rb");
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
);
171 static void test_load_v2(void)
173 QEMUFile
*fsave
= qemu_fdopen(dup_temp_fd(true), "wb");
178 0, 0, 0, 0, 0, 0, 0, 40, /* d */
180 0, 0, 0, 0, 0, 0, 0, 60, /* f */
181 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
183 qemu_put_buffer(fsave
, buf
, sizeof(buf
));
186 QEMUFile
*loading
= qemu_fdopen(dup_temp_fd(false), "rb");
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
);
198 static bool test_skip(void *opaque
, int version_id
)
200 TestStruct
*t
= (TestStruct
*)opaque
;
204 static const VMStateDescription vmstate_skipping
= {
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()
220 static void test_save_noskip(void)
222 QEMUFile
*fsave
= qemu_fdopen(dup_temp_fd(true), "wb");
223 TestStruct obj
= { .a
= 1, .b
= 2, .c
= 3, .d
= 4, .e
= 5, .f
= 6,
225 vmstate_save_state(fsave
, &vmstate_skipping
, &obj
);
226 g_assert(!qemu_file_get_error(fsave
));
229 QEMUFile
*loading
= qemu_fdopen(dup_temp_fd(false), "rb");
230 uint8_t expected
[] = {
234 0, 0, 0, 0, 0, 0, 0, 4, /* d */
236 0, 0, 0, 0, 0, 0, 0, 6, /* f */
238 uint8_t result
[sizeof(expected
)];
239 g_assert_cmpint(qemu_get_buffer(loading
, result
, sizeof(result
)), ==,
241 g_assert(!qemu_file_get_error(loading
));
242 g_assert_cmpint(memcmp(result
, expected
, sizeof(result
)), ==, 0);
245 qemu_get_byte(loading
);
246 g_assert_cmpint(qemu_file_get_error(loading
), ==, -EIO
);
248 qemu_fclose(loading
);
251 static void test_save_skip(void)
253 QEMUFile
*fsave
= qemu_fdopen(dup_temp_fd(true), "wb");
254 TestStruct obj
= { .a
= 1, .b
= 2, .c
= 3, .d
= 4, .e
= 5, .f
= 6,
256 vmstate_save_state(fsave
, &vmstate_skipping
, &obj
);
257 g_assert(!qemu_file_get_error(fsave
));
260 QEMUFile
*loading
= qemu_fdopen(dup_temp_fd(false), "rb");
261 uint8_t expected
[] = {
264 0, 0, 0, 0, 0, 0, 0, 4, /* d */
265 0, 0, 0, 0, 0, 0, 0, 6, /* f */
267 uint8_t result
[sizeof(expected
)];
268 g_assert_cmpint(qemu_get_buffer(loading
, result
, sizeof(result
)), ==,
270 g_assert(!qemu_file_get_error(loading
));
271 g_assert_cmpint(memcmp(result
, expected
, sizeof(result
)), ==, 0);
275 qemu_get_byte(loading
);
276 g_assert_cmpint(qemu_file_get_error(loading
), ==, -EIO
);
278 qemu_fclose(loading
);
281 static void test_load_noskip(void)
283 QEMUFile
*fsave
= qemu_fdopen(dup_temp_fd(true), "wb");
288 0, 0, 0, 0, 0, 0, 0, 40, /* d */
290 0, 0, 0, 0, 0, 0, 0, 60, /* f */
291 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
293 qemu_put_buffer(fsave
, buf
, sizeof(buf
));
296 QEMUFile
*loading
= qemu_fdopen(dup_temp_fd(false), "rb");
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
);
309 static void test_load_skip(void)
311 QEMUFile
*fsave
= qemu_fdopen(dup_temp_fd(true), "wb");
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 */
319 qemu_put_buffer(fsave
, buf
, sizeof(buf
));
322 QEMUFile
*loading
= qemu_fdopen(dup_temp_fd(false), "rb");
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
);
335 int main(int argc
, char **argv
)
337 temp_fd
= mkstemp(temp_file
);
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
);