summaryrefslogtreecommitdiffstats
path: root/tests/test-char.c
diff options
context:
space:
mode:
authorPeter Maydell2016-10-24 16:03:09 +0200
committerPeter Maydell2016-10-24 16:03:09 +0200
commita3ae21ec3fe036f536dc94cad735931777143103 (patch)
treeb8110b4ad3a2a21f68f9273acfb704c2c49ceb19 /tests/test-char.c
parentMerge remote-tracking branch 'remotes/sstabellini/tags/xen-20161021-tag' into... (diff)
parentexec.c: workaround regression caused by alignment change in d2f39ad (diff)
downloadqemu-a3ae21ec3fe036f536dc94cad735931777143103.tar.gz
qemu-a3ae21ec3fe036f536dc94cad735931777143103.tar.xz
qemu-a3ae21ec3fe036f536dc94cad735931777143103.zip
Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging
* KVM run_on_cpu fix (Alex) * atomic usage fixes (Emilio, me) * hugetlbfs alignment fix (Haozhong) * CharBackend refactoring (Marc-André) * test-i386 fixes (me) * MemoryListener optimizations (me) * Miscellaneous bugfixes (me) * iSER support (Roy) * --version formatting (Thomas) # gpg: Signature made Mon 24 Oct 2016 14:46:19 BST # gpg: using RSA key 0xBFFBD25F78C7AE83 # gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" # gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" # Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4 E2F7 7E15 100C CD36 69B1 # Subkey fingerprint: F133 3857 4B66 2389 866C 7682 BFFB D25F 78C7 AE83 * remotes/bonzini/tags/for-upstream: (50 commits) exec.c: workaround regression caused by alignment change in d2f39ad char: remove explicit_be_open from CharDriverState char: use common error path in qmp_chardev_add char: replace avail_connections char: remove unused qemu_chr_fe_event char: use an enum for CHR_EVENT char: remove unused CHR_EVENT_FOCUS char: move fe_open in CharBackend char: remove explicit_fe_open, use a set_handlers argument char: rename chr_close/chr_free char: move front end handlers in CharBackend tests: start chardev unit tests char: make some qemu_chr_fe skip if no driver char: replace qemu_chr_claim/release with qemu_chr_fe_init/deinit vhost-user: only initialize queue 0 CharBackend char: fold qemu_chr_set_handlers in qemu_chr_fe_set_handlers char: use qemu_chr_fe* functions with CharBackend argument colo: claim in find_and_check_chardev char: rename some frontend functions char: remaining switch to CharBackend in frontend ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'tests/test-char.c')
-rw-r--r--tests/test-char.c253
1 files changed, 253 insertions, 0 deletions
diff --git a/tests/test-char.c b/tests/test-char.c
new file mode 100644
index 0000000000..241685afbb
--- /dev/null
+++ b/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, true);
+
+ 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, true);
+ 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, true);
+ 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, 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_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();
+}