These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / tests / test-io-task.c
1 /*
2  * QEMU I/O task tests
3  *
4  * Copyright (c) 2015 Red Hat, Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "qemu/osdep.h"
22 #include <glib.h>
23
24 #include "io/task.h"
25 #include "qapi/error.h"
26
27 #define TYPE_DUMMY "qemu:dummy"
28
29 typedef struct DummyObject DummyObject;
30 typedef struct DummyObjectClass DummyObjectClass;
31
32 struct DummyObject {
33     Object parent;
34 };
35
36 struct DummyObjectClass {
37     ObjectClass parent;
38 };
39
40 static const TypeInfo dummy_info = {
41     .parent = TYPE_OBJECT,
42     .name = TYPE_DUMMY,
43     .instance_size = sizeof(DummyObject),
44     .class_size = sizeof(DummyObjectClass),
45 };
46
47 struct TestTaskData {
48     Object *source;
49     Error *err;
50     bool freed;
51 };
52
53
54 static void task_callback(Object *source,
55                           Error *err,
56                           gpointer opaque)
57 {
58     struct TestTaskData *data = opaque;
59
60     data->source = source;
61     data->err = err;
62 }
63
64
65 static void test_task_complete(void)
66 {
67     QIOTask *task;
68     Object *obj = object_new(TYPE_DUMMY);
69     Object *src;
70     struct TestTaskData data = { NULL, NULL, false };
71
72     task = qio_task_new(obj, task_callback, &data, NULL);
73     src = qio_task_get_source(task);
74
75     qio_task_complete(task);
76
77     g_assert(obj == src);
78
79     object_unref(obj);
80     object_unref(src);
81
82     g_assert(data.source == obj);
83     g_assert(data.err == NULL);
84     g_assert(data.freed == false);
85 }
86
87
88 static void task_data_free(gpointer opaque)
89 {
90     struct TestTaskData *data = opaque;
91
92     data->freed = true;
93 }
94
95
96 static void test_task_data_free(void)
97 {
98     QIOTask *task;
99     Object *obj = object_new(TYPE_DUMMY);
100     struct TestTaskData data = { NULL, NULL, false };
101
102     task = qio_task_new(obj, task_callback, &data, task_data_free);
103
104     qio_task_complete(task);
105
106     object_unref(obj);
107
108     g_assert(data.source == obj);
109     g_assert(data.err == NULL);
110     g_assert(data.freed == true);
111 }
112
113
114 static void test_task_error(void)
115 {
116     QIOTask *task;
117     Object *obj = object_new(TYPE_DUMMY);
118     struct TestTaskData data = { NULL, NULL, false };
119     Error *err = NULL;
120
121     task = qio_task_new(obj, task_callback, &data, NULL);
122
123     error_setg(&err, "Some error");
124
125     qio_task_abort(task, err);
126
127     error_free(err);
128     object_unref(obj);
129
130     g_assert(data.source == obj);
131     g_assert(data.err == err);
132     g_assert(data.freed == false);
133
134 }
135
136
137 struct TestThreadWorkerData {
138     Object *source;
139     Error *err;
140     bool fail;
141     GThread *worker;
142     GThread *complete;
143     GMainLoop *loop;
144 };
145
146 static int test_task_thread_worker(QIOTask *task,
147                                    Error **errp,
148                                    gpointer opaque)
149 {
150     struct TestThreadWorkerData *data = opaque;
151
152     data->worker = g_thread_self();
153
154     if (data->fail) {
155         error_setg(errp, "Testing fail");
156         return -1;
157     }
158
159     return 0;
160 }
161
162
163 static void test_task_thread_callback(Object *source,
164                                       Error *err,
165                                       gpointer opaque)
166 {
167     struct TestThreadWorkerData *data = opaque;
168
169     data->source = source;
170     data->err = err;
171
172     data->complete = g_thread_self();
173
174     g_main_loop_quit(data->loop);
175 }
176
177
178 static void test_task_thread_complete(void)
179 {
180     QIOTask *task;
181     Object *obj = object_new(TYPE_DUMMY);
182     struct TestThreadWorkerData data = { 0 };
183     GThread *self;
184
185     data.loop = g_main_loop_new(g_main_context_default(),
186                                 TRUE);
187
188     task = qio_task_new(obj,
189                         test_task_thread_callback,
190                         &data,
191                         NULL);
192
193     qio_task_run_in_thread(task,
194                            test_task_thread_worker,
195                            &data,
196                            NULL);
197
198     g_main_loop_run(data.loop);
199
200     g_main_loop_unref(data.loop);
201     object_unref(obj);
202
203     g_assert(data.source == obj);
204     g_assert(data.err == NULL);
205
206     self = g_thread_self();
207
208     /* Make sure the test_task_thread_worker actually got
209      * run in a different thread */
210     g_assert(data.worker != self);
211
212     /* And that the test_task_thread_callback got rnu in
213      * the main loop thread (ie this one) */
214     g_assert(data.complete == self);
215 }
216
217
218 static void test_task_thread_error(void)
219 {
220     QIOTask *task;
221     Object *obj = object_new(TYPE_DUMMY);
222     struct TestThreadWorkerData data = { 0 };
223     GThread *self;
224
225     data.loop = g_main_loop_new(g_main_context_default(),
226                                 TRUE);
227     data.fail = true;
228
229     task = qio_task_new(obj,
230                         test_task_thread_callback,
231                         &data,
232                         NULL);
233
234     qio_task_run_in_thread(task,
235                            test_task_thread_worker,
236                            &data,
237                            NULL);
238
239     g_main_loop_run(data.loop);
240
241     g_main_loop_unref(data.loop);
242     object_unref(obj);
243
244     g_assert(data.source == obj);
245     g_assert(data.err != NULL);
246
247     self = g_thread_self();
248
249     /* Make sure the test_task_thread_worker actually got
250      * run in a different thread */
251     g_assert(data.worker != self);
252
253     /* And that the test_task_thread_callback got rnu in
254      * the main loop thread (ie this one) */
255     g_assert(data.complete == self);
256 }
257
258
259 int main(int argc, char **argv)
260 {
261     g_test_init(&argc, &argv, NULL);
262     module_call_init(MODULE_INIT_QOM);
263     type_register_static(&dummy_info);
264     g_test_add_func("/crypto/task/complete", test_task_complete);
265     g_test_add_func("/crypto/task/datafree", test_task_data_free);
266     g_test_add_func("/crypto/task/error", test_task_error);
267     g_test_add_func("/crypto/task/thread_complete", test_task_thread_complete);
268     g_test_add_func("/crypto/task/thread_error", test_task_thread_error);
269     return g_test_run();
270 }