xref: /qemu/tests/unit/test-qmp-event.c (revision 15280c360e54a65e2c7be1a47bfbe41dce1ef986)
1 /*
2  * qapi event unit-tests.
3  *
4  * Copyright (c) 2014 Wenchao Xia
5  *
6  * Authors:
7  *  Wenchao Xia   <wenchaoqemu@gmail.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 
14 #include "qemu/osdep.h"
15 
16 #include "qemu-common.h"
17 #include "test-qapi-visit.h"
18 #include "test-qapi-event.h"
19 #include "qapi/error.h"
20 #include "qapi/qmp/qbool.h"
21 #include "qapi/qmp/qnum.h"
22 #include "qapi/qmp/qobject.h"
23 #include "qapi/qmp/qstring.h"
24 #include "qapi/qmp-event.h"
25 
26 typedef struct TestEventData {
27     QDict *expect;
28 } TestEventData;
29 
30 typedef struct QDictCmpData {
31     QDict *expect;
32     bool result;
33 } QDictCmpData;
34 
35 TestEventData *test_event_data;
36 static CompatGMutex test_event_lock;
37 
38 /* Only compares bool, int, string */
39 static
40 void qdict_cmp_do_simple(const char *key, QObject *obj1, void *opaque)
41 
42 {
43     QObject *obj2;
44     QDictCmpData d_new, *d = opaque;
45     int64_t val1, val2;
46 
47     if (!d->result) {
48         return;
49     }
50 
51     obj2 = qdict_get(d->expect, key);
52     if (!obj2) {
53         d->result = false;
54         return;
55     }
56 
57     if (qobject_type(obj1) != qobject_type(obj2)) {
58         d->result = false;
59         return;
60     }
61 
62     switch (qobject_type(obj1)) {
63     case QTYPE_QBOOL:
64         d->result = (qbool_get_bool(qobject_to_qbool(obj1)) ==
65                      qbool_get_bool(qobject_to_qbool(obj2)));
66         return;
67     case QTYPE_QNUM:
68         g_assert(qnum_get_try_int(qobject_to_qnum(obj1), &val1));
69         g_assert(qnum_get_try_int(qobject_to_qnum(obj2), &val2));
70         d->result = val1 == val2;
71         return;
72     case QTYPE_QSTRING:
73         d->result = g_strcmp0(qstring_get_str(qobject_to_qstring(obj1)),
74                               qstring_get_str(qobject_to_qstring(obj2))) == 0;
75         return;
76     case QTYPE_QDICT:
77         d_new.expect = qobject_to_qdict(obj2);
78         d_new.result = true;
79         qdict_iter(qobject_to_qdict(obj1), qdict_cmp_do_simple, &d_new);
80         d->result = d_new.result;
81         return;
82     default:
83         abort();
84     }
85 }
86 
87 static bool qdict_cmp_simple(QDict *a, QDict *b)
88 {
89     QDictCmpData d;
90 
91     d.expect = b;
92     d.result = true;
93     qdict_iter(a, qdict_cmp_do_simple, &d);
94     return d.result;
95 }
96 
97 /* This function is hooked as final emit function, which can verify the
98    correctness. */
99 static void event_test_emit(test_QAPIEvent event, QDict *d, Error **errp)
100 {
101     QDict *t;
102     int64_t s, ms;
103 
104     /* Verify that we have timestamp, then remove it to compare other fields */
105     t = qdict_get_qdict(d, "timestamp");
106     g_assert(t);
107     s = qdict_get_try_int(t, "seconds", -2);
108     ms = qdict_get_try_int(t, "microseconds", -2);
109     if (s == -1) {
110         g_assert(ms == -1);
111     } else {
112         g_assert(s >= 0);
113         g_assert(ms >= 0 && ms <= 999999);
114     }
115     g_assert(qdict_size(t) == 2);
116 
117     qdict_del(d, "timestamp");
118 
119     g_assert(qdict_cmp_simple(d, test_event_data->expect));
120 
121 }
122 
123 static void event_prepare(TestEventData *data,
124                           const void *unused)
125 {
126     /* Global variable test_event_data was used to pass the expectation, so
127        test cases can't be executed at same time. */
128     g_mutex_lock(&test_event_lock);
129 
130     data->expect = qdict_new();
131     test_event_data = data;
132 }
133 
134 static void event_teardown(TestEventData *data,
135                            const void *unused)
136 {
137     QDECREF(data->expect);
138     test_event_data = NULL;
139 
140     g_mutex_unlock(&test_event_lock);
141 }
142 
143 static void event_test_add(const char *testpath,
144                            void (*test_func)(TestEventData *data,
145                                              const void *user_data))
146 {
147     g_test_add(testpath, TestEventData, NULL, event_prepare, test_func,
148                event_teardown);
149 }
150 
151 
152 /* Test cases */
153 
154 static void test_event_a(TestEventData *data,
155                          const void *unused)
156 {
157     QDict *d;
158     d = data->expect;
159     qdict_put_str(d, "event", "EVENT_A");
160     qapi_event_send_event_a(&error_abort);
161 }
162 
163 static void test_event_b(TestEventData *data,
164                          const void *unused)
165 {
166     QDict *d;
167     d = data->expect;
168     qdict_put_str(d, "event", "EVENT_B");
169     qapi_event_send_event_b(&error_abort);
170 }
171 
172 static void test_event_c(TestEventData *data,
173                          const void *unused)
174 {
175     QDict *d, *d_data, *d_b;
176 
177     UserDefOne b;
178     b.integer = 2;
179     b.string = g_strdup("test1");
180     b.has_enum1 = false;
181 
182     d_b = qdict_new();
183     qdict_put_int(d_b, "integer", 2);
184     qdict_put_str(d_b, "string", "test1");
185 
186     d_data = qdict_new();
187     qdict_put_int(d_data, "a", 1);
188     qdict_put(d_data, "b", d_b);
189     qdict_put_str(d_data, "c", "test2");
190 
191     d = data->expect;
192     qdict_put_str(d, "event", "EVENT_C");
193     qdict_put(d, "data", d_data);
194 
195     qapi_event_send_event_c(true, 1, true, &b, "test2", &error_abort);
196 
197     g_free(b.string);
198 }
199 
200 /* Complex type */
201 static void test_event_d(TestEventData *data,
202                          const void *unused)
203 {
204     UserDefOne struct1;
205     EventStructOne a;
206     QDict *d, *d_data, *d_a, *d_struct1;
207 
208     struct1.integer = 2;
209     struct1.string = g_strdup("test1");
210     struct1.has_enum1 = true;
211     struct1.enum1 = ENUM_ONE_VALUE1;
212 
213     a.struct1 = &struct1;
214     a.string = g_strdup("test2");
215     a.has_enum2 = true;
216     a.enum2 = ENUM_ONE_VALUE2;
217 
218     d_struct1 = qdict_new();
219     qdict_put_int(d_struct1, "integer", 2);
220     qdict_put_str(d_struct1, "string", "test1");
221     qdict_put_str(d_struct1, "enum1", "value1");
222 
223     d_a = qdict_new();
224     qdict_put(d_a, "struct1", d_struct1);
225     qdict_put_str(d_a, "string", "test2");
226     qdict_put_str(d_a, "enum2", "value2");
227 
228     d_data = qdict_new();
229     qdict_put(d_data, "a", d_a);
230     qdict_put_str(d_data, "b", "test3");
231     qdict_put_str(d_data, "enum3", "value3");
232 
233     d = data->expect;
234     qdict_put_str(d, "event", "EVENT_D");
235     qdict_put(d, "data", d_data);
236 
237     qapi_event_send_event_d(&a, "test3", false, NULL, true, ENUM_ONE_VALUE3,
238                            &error_abort);
239 
240     g_free(struct1.string);
241     g_free(a.string);
242 }
243 
244 int main(int argc, char **argv)
245 {
246 #if !GLIB_CHECK_VERSION(2, 31, 0)
247     if (!g_thread_supported()) {
248        g_thread_init(NULL);
249     }
250 #endif
251 
252     qmp_event_set_func_emit(event_test_emit);
253 
254     g_test_init(&argc, &argv, NULL);
255 
256     event_test_add("/event/event_a", test_event_a);
257     event_test_add("/event/event_b", test_event_b);
258     event_test_add("/event/event_c", test_event_c);
259     event_test_add("/event/event_d", test_event_d);
260     g_test_run();
261 
262     return 0;
263 }
264