Per supported platforms doc[1], the various min glib on relevant distros is: RHEL-7: 2.50.3 Debian (Stretch): 2.50.3 Debian (Jessie): 2.42.1 OpenBSD (Ports): 2.54.3 FreeBSD (Ports): 2.50.3 OpenSUSE Leap 15: 2.54.3 SLE12-SP2: 2.48.2 Ubuntu (Xenial): 2.48.0 macOS (Homebrew): 2.56.0 This suggests that a minimum glib of 2.42 is a reasonable target. The GLibC compile farm, however, uses Ubuntu 14.04 (Trusty) which only has glib 2.40.0, and this is needed for testing during merge. Thus an exception is made to the documented platform support policy to allow for all three current LTS releases to be supported. Docker jobs that not longer satisfy this new min version are removed. [1] https://qemu.weilnetz.de/doc/qemu-doc.html#Supported-build-platforms Reviewed-by: Thomas Huth <thuth@redhat.com> Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
257 lines
6.3 KiB
C
257 lines
6.3 KiB
C
/*
|
|
* qapi event unit-tests.
|
|
*
|
|
* Copyright (c) 2014 Wenchao Xia
|
|
*
|
|
* Authors:
|
|
* Wenchao Xia <wenchaoqemu@gmail.com>
|
|
*
|
|
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
|
|
* See the COPYING.LIB file in the top-level directory.
|
|
*
|
|
*/
|
|
|
|
#include "qemu/osdep.h"
|
|
|
|
#include "qemu-common.h"
|
|
#include "qapi/error.h"
|
|
#include "qapi/qmp/qbool.h"
|
|
#include "qapi/qmp/qdict.h"
|
|
#include "qapi/qmp/qnum.h"
|
|
#include "qapi/qmp/qstring.h"
|
|
#include "qapi/qmp-event.h"
|
|
#include "test-qapi-events.h"
|
|
|
|
typedef struct TestEventData {
|
|
QDict *expect;
|
|
} TestEventData;
|
|
|
|
typedef struct QDictCmpData {
|
|
QDict *expect;
|
|
bool result;
|
|
} QDictCmpData;
|
|
|
|
TestEventData *test_event_data;
|
|
static GMutex test_event_lock;
|
|
|
|
/* Only compares bool, int, string */
|
|
static
|
|
void qdict_cmp_do_simple(const char *key, QObject *obj1, void *opaque)
|
|
|
|
{
|
|
QObject *obj2;
|
|
QDictCmpData d_new, *d = opaque;
|
|
int64_t val1, val2;
|
|
|
|
if (!d->result) {
|
|
return;
|
|
}
|
|
|
|
obj2 = qdict_get(d->expect, key);
|
|
if (!obj2) {
|
|
d->result = false;
|
|
return;
|
|
}
|
|
|
|
if (qobject_type(obj1) != qobject_type(obj2)) {
|
|
d->result = false;
|
|
return;
|
|
}
|
|
|
|
switch (qobject_type(obj1)) {
|
|
case QTYPE_QBOOL:
|
|
d->result = (qbool_get_bool(qobject_to(QBool, obj1)) ==
|
|
qbool_get_bool(qobject_to(QBool, obj2)));
|
|
return;
|
|
case QTYPE_QNUM:
|
|
g_assert(qnum_get_try_int(qobject_to(QNum, obj1), &val1));
|
|
g_assert(qnum_get_try_int(qobject_to(QNum, obj2), &val2));
|
|
d->result = val1 == val2;
|
|
return;
|
|
case QTYPE_QSTRING:
|
|
d->result = g_strcmp0(qstring_get_str(qobject_to(QString, obj1)),
|
|
qstring_get_str(qobject_to(QString, obj2))) == 0;
|
|
return;
|
|
case QTYPE_QDICT:
|
|
d_new.expect = qobject_to(QDict, obj2);
|
|
d_new.result = true;
|
|
qdict_iter(qobject_to(QDict, obj1), qdict_cmp_do_simple, &d_new);
|
|
d->result = d_new.result;
|
|
return;
|
|
default:
|
|
abort();
|
|
}
|
|
}
|
|
|
|
static bool qdict_cmp_simple(QDict *a, QDict *b)
|
|
{
|
|
QDictCmpData d;
|
|
|
|
d.expect = b;
|
|
d.result = true;
|
|
qdict_iter(a, qdict_cmp_do_simple, &d);
|
|
return d.result;
|
|
}
|
|
|
|
/* This function is hooked as final emit function, which can verify the
|
|
correctness. */
|
|
static void event_test_emit(test_QAPIEvent event, QDict *d, Error **errp)
|
|
{
|
|
QDict *t;
|
|
int64_t s, ms;
|
|
|
|
/* Verify that we have timestamp, then remove it to compare other fields */
|
|
t = qdict_get_qdict(d, "timestamp");
|
|
g_assert(t);
|
|
s = qdict_get_try_int(t, "seconds", -2);
|
|
ms = qdict_get_try_int(t, "microseconds", -2);
|
|
if (s == -1) {
|
|
g_assert(ms == -1);
|
|
} else {
|
|
g_assert(s >= 0);
|
|
g_assert(ms >= 0 && ms <= 999999);
|
|
}
|
|
g_assert(qdict_size(t) == 2);
|
|
|
|
qdict_del(d, "timestamp");
|
|
|
|
g_assert(qdict_cmp_simple(d, test_event_data->expect));
|
|
|
|
}
|
|
|
|
static void event_prepare(TestEventData *data,
|
|
const void *unused)
|
|
{
|
|
/* Global variable test_event_data was used to pass the expectation, so
|
|
test cases can't be executed at same time. */
|
|
g_mutex_lock(&test_event_lock);
|
|
|
|
data->expect = qdict_new();
|
|
test_event_data = data;
|
|
}
|
|
|
|
static void event_teardown(TestEventData *data,
|
|
const void *unused)
|
|
{
|
|
qobject_unref(data->expect);
|
|
test_event_data = NULL;
|
|
|
|
g_mutex_unlock(&test_event_lock);
|
|
}
|
|
|
|
static void event_test_add(const char *testpath,
|
|
void (*test_func)(TestEventData *data,
|
|
const void *user_data))
|
|
{
|
|
g_test_add(testpath, TestEventData, NULL, event_prepare, test_func,
|
|
event_teardown);
|
|
}
|
|
|
|
|
|
/* Test cases */
|
|
|
|
static void test_event_a(TestEventData *data,
|
|
const void *unused)
|
|
{
|
|
QDict *d;
|
|
d = data->expect;
|
|
qdict_put_str(d, "event", "EVENT_A");
|
|
qapi_event_send_event_a(&error_abort);
|
|
}
|
|
|
|
static void test_event_b(TestEventData *data,
|
|
const void *unused)
|
|
{
|
|
QDict *d;
|
|
d = data->expect;
|
|
qdict_put_str(d, "event", "EVENT_B");
|
|
qapi_event_send_event_b(&error_abort);
|
|
}
|
|
|
|
static void test_event_c(TestEventData *data,
|
|
const void *unused)
|
|
{
|
|
QDict *d, *d_data, *d_b;
|
|
|
|
UserDefOne b;
|
|
b.integer = 2;
|
|
b.string = g_strdup("test1");
|
|
b.has_enum1 = false;
|
|
|
|
d_b = qdict_new();
|
|
qdict_put_int(d_b, "integer", 2);
|
|
qdict_put_str(d_b, "string", "test1");
|
|
|
|
d_data = qdict_new();
|
|
qdict_put_int(d_data, "a", 1);
|
|
qdict_put(d_data, "b", d_b);
|
|
qdict_put_str(d_data, "c", "test2");
|
|
|
|
d = data->expect;
|
|
qdict_put_str(d, "event", "EVENT_C");
|
|
qdict_put(d, "data", d_data);
|
|
|
|
qapi_event_send_event_c(true, 1, true, &b, "test2", &error_abort);
|
|
|
|
g_free(b.string);
|
|
}
|
|
|
|
/* Complex type */
|
|
static void test_event_d(TestEventData *data,
|
|
const void *unused)
|
|
{
|
|
UserDefOne struct1;
|
|
EventStructOne a;
|
|
QDict *d, *d_data, *d_a, *d_struct1;
|
|
|
|
struct1.integer = 2;
|
|
struct1.string = g_strdup("test1");
|
|
struct1.has_enum1 = true;
|
|
struct1.enum1 = ENUM_ONE_VALUE1;
|
|
|
|
a.struct1 = &struct1;
|
|
a.string = g_strdup("test2");
|
|
a.has_enum2 = true;
|
|
a.enum2 = ENUM_ONE_VALUE2;
|
|
|
|
d_struct1 = qdict_new();
|
|
qdict_put_int(d_struct1, "integer", 2);
|
|
qdict_put_str(d_struct1, "string", "test1");
|
|
qdict_put_str(d_struct1, "enum1", "value1");
|
|
|
|
d_a = qdict_new();
|
|
qdict_put(d_a, "struct1", d_struct1);
|
|
qdict_put_str(d_a, "string", "test2");
|
|
qdict_put_str(d_a, "enum2", "value2");
|
|
|
|
d_data = qdict_new();
|
|
qdict_put(d_data, "a", d_a);
|
|
qdict_put_str(d_data, "b", "test3");
|
|
qdict_put_str(d_data, "enum3", "value3");
|
|
|
|
d = data->expect;
|
|
qdict_put_str(d, "event", "EVENT_D");
|
|
qdict_put(d, "data", d_data);
|
|
|
|
qapi_event_send_event_d(&a, "test3", false, NULL, true, ENUM_ONE_VALUE3,
|
|
&error_abort);
|
|
|
|
g_free(struct1.string);
|
|
g_free(a.string);
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
qmp_event_set_func_emit(event_test_emit);
|
|
|
|
g_test_init(&argc, &argv, NULL);
|
|
|
|
event_test_add("/event/event_a", test_event_a);
|
|
event_test_add("/event/event_b", test_event_b);
|
|
event_test_add("/event/event_c", test_event_c);
|
|
event_test_add("/event/event_d", test_event_d);
|
|
g_test_run();
|
|
|
|
return 0;
|
|
}
|