* Fabiano Rosas ([email protected]) wrote:
> The following patches will touch HMP readline completion for migration
> parameters, add a test case.
> 
> The test puts the monitor on a chardev via socket and bypasses qtest
> facilities because it needs to emit raw codes to readline. It
> therefore requires a couple of new helpers to read/write to the
> monitor socket.
> 
> Usage:
> QTEST_QEMU_BINARY=./qemu-system-x86_64 \
> ./tests/qtest/migration-test --full -p /x86_64/migration/hmp/completion
> 
> Signed-off-by: Fabiano Rosas <[email protected]>
> ---

> +static void hmp_sock_read(int fd, char *buf, size_t buf_sz)
> +{
> +    char *p = buf;
> +    size_t sz = buf_sz - 1;
> +
> +    assert(fd >= 0);
> +    memset(buf, 0, buf_sz);
> +
> +    while (sz > 0) {
> +        ssize_t r = read(fd, p, sz);
> +        char *prompt;
> +
> +        if (!r) {
> +            break;
> +        } else if (r < 0) {
> +            if (errno == EINTR) {
> +                continue;
> +            }
> +            g_assert_not_reached();
> +        }
> +
> +        p += r;
> +        sz -= r;
> +
> +        prompt = strstr(buf, "(qemu) ");
> +        if (prompt) {
> +            *prompt = '\0';

I'm a bit confused by what you want the output to look like after this,
are you assuming this is the end of the string you're reading so truncation
is OK?

> +            break;
> +        }
> +    }
> +}
> +
> +static int comp(const void *a, const void *b)
> +{
> +    return strcmp(*(const char **) a, *(const char **) b);
> +}

Can you use qemu_pstrcmp0 there? (Maybe with g_ptr_array and g_ptr_array_sort is
what adds to some of the other questions below?)

> +static void get_migration_opts_sorted(GString *exp, const char * const 
> *lookup, int n)
> +{
> +    g_autofree char **opts_array = g_new0(char *, n);
> +    uint8_t i;
> +
> +    for (i = 0; i < n; i++) {
> +        opts_array[i] = g_strdup(lookup[i]);
> +    }

If you made opts_array one element larger, and added a NULL at the end could 
you...

> +    qsort(opts_array, n, sizeof(char *), comp);
> +
> +    for (i = 0; i < n; i++) {
> +        g_string_append(exp, opts_array[i]);
> +        if (i + 1 != n) {
> +            g_string_append(exp, " ");
> +        }
> +    }

Use g_strjoinv here?

> +    for (i = 0; i < n; i++) {
> +        g_free(opts_array[i]);
> +    }
> +}

Dave

> +static void hmp_completion_single(int fd, const struct HMPTestData *t)
> +{
> +    g_autoptr(GString) exp = g_string_new("");
> +    char buf[8192];
> +    char *output;
> +
> +    test_case_line = t->line;
> +
> +    if (g_str_equal(t->output1, "@caps@")) {
> +        g_string_append(exp, "migrate_set_capability ");
> +        get_migration_opts_sorted(exp, MigrationCapability_lookup.array,
> +                                  MIGRATION_CAPABILITY__MAX);
> +    } else if (g_str_equal(t->output1, "@params@")) {
> +        g_string_append(exp, "migrate_set_parameter ");
> +        get_migration_opts_sorted(exp, MigrationParameter_lookup.array,
> +                                  MIGRATION_PARAMETER__MAX);
> +    } else {
> +        g_string_append(exp, t->output1);
> +    }
> +
> +    hmp_sock_write(fd, t->input1);
> +    hmp_sock_read(fd, buf, sizeof(buf));
> +
> +    /*
> +     * readline first rewrites the input to the common root of the
> +     * completions, then outputs the completion suggestions:
> +     *
> +     * (qemu) info migr<TAB>
> +     * (qemu) migrate migrate_parameters
> +     * migrate_capabilities ...
> +     */
> +    output = strstr(buf, t->input2);
> +    assert_hmp_match_text(exp->str, output);
> +
> +    /* ^U backward kill line */
> +    hmp_sock_write(fd, "\x15");
> +}
> +
> +static void test_hmp_completion(char *name, MigrateCommon *args)
> +{
> +    g_autofree char *cmdline;
> +    char buf[1024];
> +    QTestState *qts;
> +    int sockfds[2];
> +
> +    assert(!qemu_socketpair(AF_UNIX, SOCK_STREAM, 0, sockfds));
> +    qemu_clear_cloexec(sockfds[1]);
> +
> +    cmdline = g_strdup_printf("-chardev socket,id=mon0,fd=%d "
> +                              "-mon chardev=mon0,mode=readline -S",
> +                              sockfds[1]);
> +    qts = qtest_init(cmdline);
> +    close(sockfds[1]);
> +
> +    /* read HMP banner */
> +    hmp_sock_read(sockfds[0], buf, sizeof(buf));
> +
> +    for (int i = 0; i < G_N_ELEMENTS(completion_cases); i++) {
> +        hmp_completion_single(sockfds[0], &completion_cases[i]);
> +    }
> +
> +    close(sockfds[0]);
> +    qtest_quit(qts);
> +}
>  #endif /* CONFIG_HMP */
>  
>  static void test_baddest(char *name, MigrateCommon *args)
> @@ -460,5 +650,7 @@ void migration_test_add_misc(MigrationTestEnv *env)
>  #ifdef CONFIG_HMP
>      migration_test_add("/migration/hmp/parameters",
>                         test_hmp_migration_parameters);
> +    migration_test_add("/migration/hmp/completion",
> +                       test_hmp_completion);
>  #endif
>  }
> -- 
> 2.53.0
> 
-- 
 -----Open up your eyes, open up your mind, open up your code -------   
/ Dr. David Alan Gilbert    |       Running GNU/Linux       | Happy  \ 
\        dave @ treblig.org |                               | In Hex /
 \ _________________________|_____ http://www.treblig.org   |_______/

Reply via email to