qemu/tests/test-char.c
<<
>>
Prefs
   1#include "qemu/osdep.h"
   2
   3#include "qemu-common.h"
   4#include "qemu/config-file.h"
   5#include "sysemu/char.h"
   6#include "sysemu/sysemu.h"
   7#include "qapi/error.h"
   8#include "qmp-commands.h"
   9
  10typedef struct FeHandler {
  11    int read_count;
  12    int last_event;
  13    char read_buf[128];
  14} FeHandler;
  15
  16static int fe_can_read(void *opaque)
  17{
  18    FeHandler *h = opaque;
  19
  20    return sizeof(h->read_buf) - h->read_count;
  21}
  22
  23static void fe_read(void *opaque, const uint8_t *buf, int size)
  24{
  25    FeHandler *h = opaque;
  26
  27    g_assert_cmpint(size, <=, fe_can_read(opaque));
  28
  29    memcpy(h->read_buf + h->read_count, buf, size);
  30    h->read_count += size;
  31}
  32
  33static void fe_event(void *opaque, int event)
  34{
  35    FeHandler *h = opaque;
  36
  37    h->last_event = event;
  38}
  39
  40#ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS
  41static void char_stdio_test_subprocess(void)
  42{
  43    CharDriverState *chr;
  44    CharBackend be;
  45    int ret;
  46
  47    chr = qemu_chr_new("label", "stdio");
  48    g_assert_nonnull(chr);
  49
  50    qemu_chr_fe_init(&be, chr, &error_abort);
  51    qemu_chr_fe_set_open(&be, true);
  52    ret = qemu_chr_fe_write(&be, (void *)"buf", 4);
  53    g_assert_cmpint(ret, ==, 4);
  54
  55    qemu_chr_fe_deinit(&be);
  56    qemu_chr_delete(chr);
  57}
  58
  59static void char_stdio_test(void)
  60{
  61    g_test_trap_subprocess("/char/stdio/subprocess", 0, 0);
  62    g_test_trap_assert_passed();
  63    g_test_trap_assert_stdout("buf");
  64}
  65#endif
  66
  67
  68static void char_ringbuf_test(void)
  69{
  70    QemuOpts *opts;
  71    CharDriverState *chr;
  72    CharBackend be;
  73    char *data;
  74    int ret;
  75
  76    opts = qemu_opts_create(qemu_find_opts("chardev"), "ringbuf-label",
  77                            1, &error_abort);
  78    qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
  79
  80    qemu_opt_set(opts, "size", "5", &error_abort);
  81    chr = qemu_chr_new_from_opts(opts, NULL);
  82    g_assert_null(chr);
  83    qemu_opts_del(opts);
  84
  85    opts = qemu_opts_create(qemu_find_opts("chardev"), "ringbuf-label",
  86                            1, &error_abort);
  87    qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
  88    qemu_opt_set(opts, "size", "2", &error_abort);
  89    chr = qemu_chr_new_from_opts(opts, &error_abort);
  90    g_assert_nonnull(chr);
  91    qemu_opts_del(opts);
  92
  93    qemu_chr_fe_init(&be, chr, &error_abort);
  94    ret = qemu_chr_fe_write(&be, (void *)"buff", 4);
  95    g_assert_cmpint(ret, ==, 4);
  96
  97    data = qmp_ringbuf_read("ringbuf-label", 4, false, 0, &error_abort);
  98    g_assert_cmpstr(data, ==, "ff");
  99    g_free(data);
 100
 101    data = qmp_ringbuf_read("ringbuf-label", 4, false, 0, &error_abort);
 102    g_assert_cmpstr(data, ==, "");
 103    g_free(data);
 104
 105    qemu_chr_fe_deinit(&be);
 106    qemu_chr_delete(chr);
 107}
 108
 109static void char_mux_test(void)
 110{
 111    QemuOpts *opts;
 112    CharDriverState *chr, *base;
 113    char *data;
 114    FeHandler h1 = { 0, }, h2 = { 0, };
 115    CharBackend chr_be1, chr_be2;
 116
 117    opts = qemu_opts_create(qemu_find_opts("chardev"), "mux-label",
 118                            1, &error_abort);
 119    qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
 120    qemu_opt_set(opts, "size", "128", &error_abort);
 121    qemu_opt_set(opts, "mux", "on", &error_abort);
 122    chr = qemu_chr_new_from_opts(opts, &error_abort);
 123    g_assert_nonnull(chr);
 124    qemu_opts_del(opts);
 125
 126    qemu_chr_fe_init(&chr_be1, chr, &error_abort);
 127    qemu_chr_fe_set_handlers(&chr_be1,
 128                             fe_can_read,
 129                             fe_read,
 130                             fe_event,
 131                             &h1,
 132                             NULL, true);
 133
 134    qemu_chr_fe_init(&chr_be2, chr, &error_abort);
 135    qemu_chr_fe_set_handlers(&chr_be2,
 136                             fe_can_read,
 137                             fe_read,
 138                             fe_event,
 139                             &h2,
 140                             NULL, true);
 141    qemu_chr_fe_take_focus(&chr_be2);
 142
 143    base = qemu_chr_find("mux-label-base");
 144    g_assert_cmpint(qemu_chr_be_can_write(base), !=, 0);
 145
 146    qemu_chr_be_write(base, (void *)"hello", 6);
 147    g_assert_cmpint(h1.read_count, ==, 0);
 148    g_assert_cmpint(h2.read_count, ==, 6);
 149    g_assert_cmpstr(h2.read_buf, ==, "hello");
 150    h2.read_count = 0;
 151
 152    /* switch focus */
 153    qemu_chr_be_write(base, (void *)"\1c", 2);
 154
 155    qemu_chr_be_write(base, (void *)"hello", 6);
 156    g_assert_cmpint(h2.read_count, ==, 0);
 157    g_assert_cmpint(h1.read_count, ==, 6);
 158    g_assert_cmpstr(h1.read_buf, ==, "hello");
 159    h1.read_count = 0;
 160
 161    /* remove first handler */
 162    qemu_chr_fe_set_handlers(&chr_be1, NULL, NULL, NULL, NULL, NULL, true);
 163    qemu_chr_be_write(base, (void *)"hello", 6);
 164    g_assert_cmpint(h1.read_count, ==, 0);
 165    g_assert_cmpint(h2.read_count, ==, 0);
 166
 167    qemu_chr_be_write(base, (void *)"\1c", 2);
 168    qemu_chr_be_write(base, (void *)"hello", 6);
 169    g_assert_cmpint(h1.read_count, ==, 0);
 170    g_assert_cmpint(h2.read_count, ==, 6);
 171    g_assert_cmpstr(h2.read_buf, ==, "hello");
 172    h2.read_count = 0;
 173
 174    /* print help */
 175    qemu_chr_be_write(base, (void *)"\1?", 2);
 176    data = qmp_ringbuf_read("mux-label-base", 128, false, 0, &error_abort);
 177    g_assert_cmpint(strlen(data), !=, 0);
 178    g_free(data);
 179
 180    qemu_chr_fe_deinit(&chr_be1);
 181    qemu_chr_fe_deinit(&chr_be2);
 182    qemu_chr_delete(chr);
 183}
 184
 185static void char_null_test(void)
 186{
 187    Error *err = NULL;
 188    CharDriverState *chr;
 189    CharBackend be;
 190    int ret;
 191
 192    chr = qemu_chr_find("label-null");
 193    g_assert_null(chr);
 194
 195    chr = qemu_chr_new("label-null", "null");
 196    chr = qemu_chr_find("label-null");
 197    g_assert_nonnull(chr);
 198
 199    g_assert(qemu_chr_has_feature(chr,
 200                 QEMU_CHAR_FEATURE_FD_PASS) == false);
 201    g_assert(qemu_chr_has_feature(chr,
 202                 QEMU_CHAR_FEATURE_RECONNECTABLE) == false);
 203
 204    /* check max avail */
 205    qemu_chr_fe_init(&be, chr, &error_abort);
 206    qemu_chr_fe_init(&be, chr, &err);
 207    error_free_or_abort(&err);
 208
 209    /* deinit & reinit */
 210    qemu_chr_fe_deinit(&be);
 211    qemu_chr_fe_init(&be, chr, &error_abort);
 212
 213    qemu_chr_fe_set_open(&be, true);
 214
 215    qemu_chr_fe_set_handlers(&be,
 216                             fe_can_read,
 217                             fe_read,
 218                             fe_event,
 219                             NULL, NULL, true);
 220
 221    ret = qemu_chr_fe_write(&be, (void *)"buf", 4);
 222    g_assert_cmpint(ret, ==, 4);
 223
 224    qemu_chr_fe_deinit(&be);
 225    qemu_chr_delete(chr);
 226}
 227
 228static void char_invalid_test(void)
 229{
 230    CharDriverState *chr;
 231
 232    chr = qemu_chr_new("label-invalid", "invalid");
 233    g_assert_null(chr);
 234}
 235
 236int main(int argc, char **argv)
 237{
 238    g_test_init(&argc, &argv, NULL);
 239
 240    module_call_init(MODULE_INIT_QOM);
 241    qemu_add_opts(&qemu_chardev_opts);
 242
 243    g_test_add_func("/char/null", char_null_test);
 244    g_test_add_func("/char/invalid", char_invalid_test);
 245    g_test_add_func("/char/ringbuf", char_ringbuf_test);
 246    g_test_add_func("/char/mux", char_mux_test);
 247#ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS
 248    g_test_add_func("/char/stdio/subprocess", char_stdio_test_subprocess);
 249    g_test_add_func("/char/stdio", char_stdio_test);
 250#endif
 251
 252    return g_test_run();
 253}
 254