Skip to content

Commit

Permalink
tests: start chardev unit tests
Browse files Browse the repository at this point in the history
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20161022095318.17775-21-marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
  • Loading branch information
elmarco authored and bonzini committed Oct 24, 2016
1 parent fa394ed commit ea3af47
Show file tree
Hide file tree
Showing 2 changed files with 257 additions and 0 deletions.
4 changes: 4 additions & 0 deletions tests/Makefile.include
Expand Up @@ -8,6 +8,8 @@ SYSEMU_TARGET_LIST := $(subst -softmmu.mak,,$(notdir \

check-unit-y = tests/check-qdict$(EXESUF)
gcov-files-check-qdict-y = qobject/qdict.c
check-unit-y = tests/test-char$(EXESUF)
gcov-files-check-qdict-y = qemu-char.c
check-unit-y += tests/check-qfloat$(EXESUF)
gcov-files-check-qfloat-y = qobject/qfloat.c
check-unit-y += tests/check-qint$(EXESUF)
Expand Down Expand Up @@ -481,6 +483,8 @@ tests/check-qnull$(EXESUF): tests/check-qnull.o $(test-util-obj-y)
tests/check-qjson$(EXESUF): tests/check-qjson.o $(test-util-obj-y)
tests/check-qom-interface$(EXESUF): tests/check-qom-interface.o $(test-qom-obj-y)
tests/check-qom-proplist$(EXESUF): tests/check-qom-proplist.o $(test-qom-obj-y)

tests/test-char$(EXESUF): tests/test-char.o qemu-char.o qemu-timer.o $(test-util-obj-y) $(qtest-obj-y) $(test-io-obj-y)
tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(test-block-obj-y)
tests/test-aio$(EXESUF): tests/test-aio.o $(test-block-obj-y)
tests/test-rfifolock$(EXESUF): tests/test-rfifolock.o $(test-util-obj-y)
Expand Down
253 changes: 253 additions & 0 deletions tests/test-char.c
@@ -0,0 +1,253 @@
#include "qemu/osdep.h"

#include "qemu-common.h"
#include "qemu/config-file.h"
#include "sysemu/char.h"
#include "sysemu/sysemu.h"
#include "qapi/error.h"
#include "qmp-commands.h"

typedef struct FeHandler {
int read_count;
int last_event;
char read_buf[128];
} FeHandler;

static int fe_can_read(void *opaque)
{
FeHandler *h = opaque;

return sizeof(h->read_buf) - h->read_count;
}

static void fe_read(void *opaque, const uint8_t *buf, int size)
{
FeHandler *h = opaque;

g_assert_cmpint(size, <=, fe_can_read(opaque));

memcpy(h->read_buf + h->read_count, buf, size);
h->read_count += size;
}

static void fe_event(void *opaque, int event)
{
FeHandler *h = opaque;

h->last_event = event;
}

#ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS
static void char_stdio_test_subprocess(void)
{
CharDriverState *chr;
CharBackend be;
int ret;

chr = qemu_chr_new("label", "stdio");
g_assert_nonnull(chr);

qemu_chr_fe_init(&be, chr, &error_abort);
qemu_chr_fe_set_open(&be, true);
ret = qemu_chr_fe_write(&be, (void *)"buf", 4);
g_assert_cmpint(ret, ==, 4);

qemu_chr_fe_deinit(&be);
qemu_chr_delete(chr);
}

static void char_stdio_test(void)
{
g_test_trap_subprocess("/char/stdio/subprocess", 0, 0);
g_test_trap_assert_passed();
g_test_trap_assert_stdout("buf");
}
#endif


static void char_ringbuf_test(void)
{
QemuOpts *opts;
CharDriverState *chr;
CharBackend be;
char *data;
int ret;

opts = qemu_opts_create(qemu_find_opts("chardev"), "ringbuf-label",
1, &error_abort);
qemu_opt_set(opts, "backend", "ringbuf", &error_abort);

qemu_opt_set(opts, "size", "5", &error_abort);
chr = qemu_chr_new_from_opts(opts, NULL);
g_assert_null(chr);
qemu_opts_del(opts);

opts = qemu_opts_create(qemu_find_opts("chardev"), "ringbuf-label",
1, &error_abort);
qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
qemu_opt_set(opts, "size", "2", &error_abort);
chr = qemu_chr_new_from_opts(opts, &error_abort);
g_assert_nonnull(chr);
qemu_opts_del(opts);

qemu_chr_fe_init(&be, chr, &error_abort);
ret = qemu_chr_fe_write(&be, (void *)"buff", 4);
g_assert_cmpint(ret, ==, 4);

data = qmp_ringbuf_read("ringbuf-label", 4, false, 0, &error_abort);
g_assert_cmpstr(data, ==, "ff");
g_free(data);

data = qmp_ringbuf_read("ringbuf-label", 4, false, 0, &error_abort);
g_assert_cmpstr(data, ==, "");
g_free(data);

qemu_chr_fe_deinit(&be);
qemu_chr_delete(chr);
}

static void char_mux_test(void)
{
QemuOpts *opts;
CharDriverState *chr, *base;
char *data;
FeHandler h1 = { 0, }, h2 = { 0, };
CharBackend chr_be1, chr_be2;

opts = qemu_opts_create(qemu_find_opts("chardev"), "mux-label",
1, &error_abort);
qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
qemu_opt_set(opts, "size", "128", &error_abort);
qemu_opt_set(opts, "mux", "on", &error_abort);
chr = qemu_chr_new_from_opts(opts, &error_abort);
g_assert_nonnull(chr);
qemu_opts_del(opts);

qemu_chr_fe_init(&chr_be1, chr, &error_abort);
qemu_chr_fe_set_handlers(&chr_be1,
fe_can_read,
fe_read,
fe_event,
&h1,
NULL);

qemu_chr_fe_init(&chr_be2, chr, &error_abort);
qemu_chr_fe_set_handlers(&chr_be2,
fe_can_read,
fe_read,
fe_event,
&h2,
NULL);
qemu_chr_fe_take_focus(&chr_be2);

base = qemu_chr_find("mux-label-base");
g_assert_cmpint(qemu_chr_be_can_write(base), !=, 0);

qemu_chr_be_write(base, (void *)"hello", 6);
g_assert_cmpint(h1.read_count, ==, 0);
g_assert_cmpint(h2.read_count, ==, 6);
g_assert_cmpstr(h2.read_buf, ==, "hello");
h2.read_count = 0;

/* switch focus */
qemu_chr_be_write(base, (void *)"\1c", 2);

qemu_chr_be_write(base, (void *)"hello", 6);
g_assert_cmpint(h2.read_count, ==, 0);
g_assert_cmpint(h1.read_count, ==, 6);
g_assert_cmpstr(h1.read_buf, ==, "hello");
h1.read_count = 0;

/* remove first handler */
qemu_chr_fe_set_handlers(&chr_be1, NULL, NULL, NULL, NULL, NULL);
qemu_chr_be_write(base, (void *)"hello", 6);
g_assert_cmpint(h1.read_count, ==, 0);
g_assert_cmpint(h2.read_count, ==, 0);

qemu_chr_be_write(base, (void *)"\1c", 2);
qemu_chr_be_write(base, (void *)"hello", 6);
g_assert_cmpint(h1.read_count, ==, 0);
g_assert_cmpint(h2.read_count, ==, 6);
g_assert_cmpstr(h2.read_buf, ==, "hello");
h2.read_count = 0;

/* print help */
qemu_chr_be_write(base, (void *)"\1?", 2);
data = qmp_ringbuf_read("mux-label-base", 128, false, 0, &error_abort);
g_assert_cmpint(strlen(data), !=, 0);
g_free(data);

qemu_chr_fe_deinit(&chr_be1);
qemu_chr_fe_deinit(&chr_be2);
qemu_chr_delete(chr);
}

static void char_null_test(void)
{
Error *err = NULL;
CharDriverState *chr;
CharBackend be;
int ret;

chr = qemu_chr_find("label-null");
g_assert_null(chr);

chr = qemu_chr_new("label-null", "null");
chr = qemu_chr_find("label-null");
g_assert_nonnull(chr);

g_assert(qemu_chr_has_feature(chr,
QEMU_CHAR_FEATURE_FD_PASS) == false);
g_assert(qemu_chr_has_feature(chr,
QEMU_CHAR_FEATURE_RECONNECTABLE) == false);

/* check max avail */
qemu_chr_fe_init(&be, chr, &error_abort);
qemu_chr_fe_init(&be, chr, &err);
error_free_or_abort(&err);

/* deinit & reinit */
qemu_chr_fe_deinit(&be);
qemu_chr_fe_init(&be, chr, &error_abort);

qemu_chr_fe_set_open(&be, true);

qemu_chr_fe_set_handlers(&be,
fe_can_read,
fe_read,
fe_event,
NULL, NULL);

ret = qemu_chr_fe_write(&be, (void *)"buf", 4);
g_assert_cmpint(ret, ==, 4);

qemu_chr_fe_deinit(&be);
qemu_chr_delete(chr);
}

static void char_invalid_test(void)
{
CharDriverState *chr;

chr = qemu_chr_new("label-invalid", "invalid");
g_assert_null(chr);
}

int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);

module_call_init(MODULE_INIT_QOM);
qemu_add_opts(&qemu_chardev_opts);

g_test_add_func("/char/null", char_null_test);
g_test_add_func("/char/invalid", char_invalid_test);
g_test_add_func("/char/ringbuf", char_ringbuf_test);
g_test_add_func("/char/mux", char_mux_test);
#ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS
g_test_add_func("/char/stdio/subprocess", char_stdio_test_subprocess);
g_test_add_func("/char/stdio", char_stdio_test);
#endif

return g_test_run();
}

0 comments on commit ea3af47

Please sign in to comment.