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