Add qemu 2.4.0
[kvmfornfv.git] / qemu / tests / drive_del-test.c
1 /*
2  * blockdev.c test cases
3  *
4  * Copyright (C) 2013-2014 Red Hat Inc.
5  *
6  * Authors:
7  *  Stefan Hajnoczi <stefanha@redhat.com>
8  *
9  * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
10  * See the COPYING.LIB file in the top-level directory.
11  */
12
13 #include <glib.h>
14 #include <string.h>
15 #include "libqtest.h"
16
17 static void drive_add(void)
18 {
19     QDict *response;
20
21     response = qmp("{'execute': 'human-monitor-command',"
22                    " 'arguments': {"
23                    "   'command-line': 'drive_add 0 if=none,id=drive0'"
24                    "}}");
25     g_assert(response);
26     g_assert_cmpstr(qdict_get_try_str(response, "return"), ==, "OK\r\n");
27     QDECREF(response);
28 }
29
30 static void drive_del(void)
31 {
32     QDict *response;
33
34     response = qmp("{'execute': 'human-monitor-command',"
35                    " 'arguments': {"
36                    "   'command-line': 'drive_del drive0'"
37                    "}}");
38     g_assert(response);
39     g_assert_cmpstr(qdict_get_try_str(response, "return"), ==, "");
40     QDECREF(response);
41 }
42
43 static void device_del(void)
44 {
45     QDict *response;
46
47     /* Complication: ignore DEVICE_DELETED event */
48     qmp_discard_response("{'execute': 'device_del',"
49                          " 'arguments': { 'id': 'dev0' } }");
50     response = qmp_receive();
51     g_assert(response);
52     g_assert(qdict_haskey(response, "return"));
53     QDECREF(response);
54 }
55
56 static void test_drive_without_dev(void)
57 {
58     /* Start with an empty drive */
59     qtest_start("-drive if=none,id=drive0");
60
61     /* Delete the drive */
62     drive_del();
63
64     /* Ensure re-adding the drive works - there should be no duplicate ID error
65      * because the old drive must be gone.
66      */
67     drive_add();
68
69     qtest_end();
70 }
71
72 static void test_after_failed_device_add(void)
73 {
74     QDict *response;
75     QDict *error;
76
77     qtest_start("-drive if=none,id=drive0");
78
79     /* Make device_add fail.  If this leaks the virtio-blk-pci device then a
80      * reference to drive0 will also be held (via qdev properties).
81      */
82     response = qmp("{'execute': 'device_add',"
83                    " 'arguments': {"
84                    "   'driver': 'virtio-blk-pci',"
85                    "   'drive': 'drive0'"
86                    "}}");
87     g_assert(response);
88     error = qdict_get_qdict(response, "error");
89     g_assert_cmpstr(qdict_get_try_str(error, "class"), ==, "GenericError");
90     QDECREF(response);
91
92     /* Delete the drive */
93     drive_del();
94
95     /* Try to re-add the drive.  This fails with duplicate IDs if a leaked
96      * virtio-blk-pci exists that holds a reference to the old drive0.
97      */
98     drive_add();
99
100     qtest_end();
101 }
102
103 static void test_drive_del_device_del(void)
104 {
105     /* Start with a drive used by a device that unplugs instantaneously */
106     qtest_start("-drive if=none,id=drive0,file=/dev/null,format=raw"
107                 " -device virtio-scsi-pci"
108                 " -device scsi-hd,drive=drive0,id=dev0");
109
110     /*
111      * Delete the drive, and then the device
112      * Doing it in this order takes notoriously tricky special paths
113      */
114     drive_del();
115     device_del();
116
117     qtest_end();
118 }
119
120 int main(int argc, char **argv)
121 {
122     const char *arch = qtest_get_arch();
123
124     g_test_init(&argc, &argv, NULL);
125
126     qtest_add_func("/drive_del/without-dev", test_drive_without_dev);
127
128     /* TODO I guess any arch with PCI would do */
129     if (!strcmp(arch, "i386") || !strcmp(arch, "x86_64")) {
130         qtest_add_func("/drive_del/after_failed_device_add",
131                        test_after_failed_device_add);
132         qtest_add_func("/blockdev/drive_del_device_del",
133                        test_drive_del_device_del);
134     }
135
136     return g_test_run();
137 }