Commit 5faf2d37 authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/huth/tags/check-20170915' into staging



Some fixes and improvements for various qtests by Eric and me.

# gpg: Signature made Fri 15 Sep 2017 08:37:21 BST
# gpg:                using RSA key 0x2ED9D774FE702DB5
# gpg: Good signature from "Thomas Huth <th.huth@gmx.de>"
# gpg:                 aka "Thomas Huth <thuth@redhat.com>"
# gpg:                 aka "Thomas Huth <huth@tuxfamily.org>"
# gpg:                 aka "Thomas Huth <th.huth@posteo.de>"
# Primary key fingerprint: 27B8 8847 EEE0 2501 18F3  EAB9 2ED9 D774 FE70 2DB5

* remotes/huth/tags/check-20170915:
  qtest: Avoid passing raw strings through hmp()
  libqtest: Remove dead qtest_instances variable
  numa-test: Use hmp()
  qtest: Don't perform side effects inside assertion
  test-qga: Kill broken and dead QGA_TEST_SIDE_EFFECTING code
  tests: Fix broken ivshmem-server-msi/-irq tests
  tests/libqtest: Use a proper error message if QTEST_QEMU_BINARY is missing
  tests/test-hmp: Remove puv3 and tricore_testboard from the blacklist
  tests: Introduce generic device hot-plug/hot-unplug functions

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents d535f5d3 7b899f4d
Loading
Loading
Loading
Loading
+58 −24
Original line number Diff line number Diff line
@@ -332,10 +332,13 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
               strcmp(words[0], "outl") == 0) {
        unsigned long addr;
        unsigned long value;
        int ret;

        g_assert(words[1] && words[2]);
        g_assert(qemu_strtoul(words[1], NULL, 0, &addr) == 0);
        g_assert(qemu_strtoul(words[2], NULL, 0, &value) == 0);
        ret = qemu_strtoul(words[1], NULL, 0, &addr);
        g_assert(ret == 0);
        ret = qemu_strtoul(words[2], NULL, 0, &value);
        g_assert(ret == 0);
        g_assert(addr <= 0xffff);

        if (words[0][3] == 'b') {
@@ -352,9 +355,11 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
        strcmp(words[0], "inl") == 0) {
        unsigned long addr;
        uint32_t value = -1U;
        int ret;

        g_assert(words[1]);
        g_assert(qemu_strtoul(words[1], NULL, 0, &addr) == 0);
        ret = qemu_strtoul(words[1], NULL, 0, &addr);
        g_assert(ret == 0);
        g_assert(addr <= 0xffff);

        if (words[0][2] == 'b') {
@@ -372,10 +377,13 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
               strcmp(words[0], "writeq") == 0) {
        uint64_t addr;
        uint64_t value;
        int ret;

        g_assert(words[1] && words[2]);
        g_assert(qemu_strtou64(words[1], NULL, 0, &addr) == 0);
        g_assert(qemu_strtou64(words[2], NULL, 0, &value) == 0);
        ret = qemu_strtou64(words[1], NULL, 0, &addr);
        g_assert(ret == 0);
        ret = qemu_strtou64(words[2], NULL, 0, &value);
        g_assert(ret == 0);

        if (words[0][5] == 'b') {
            uint8_t data = value;
@@ -401,9 +409,11 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
               strcmp(words[0], "readq") == 0) {
        uint64_t addr;
        uint64_t value = UINT64_C(-1);
        int ret;

        g_assert(words[1]);
        g_assert(qemu_strtou64(words[1], NULL, 0, &addr) == 0);
        ret = qemu_strtou64(words[1], NULL, 0, &addr);
        g_assert(ret == 0);

        if (words[0][4] == 'b') {
            uint8_t data;
@@ -427,10 +437,13 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
        uint64_t addr, len, i;
        uint8_t *data;
        char *enc;
        int ret;

        g_assert(words[1] && words[2]);
        g_assert(qemu_strtou64(words[1], NULL, 0, &addr) == 0);
        g_assert(qemu_strtou64(words[2], NULL, 0, &len) == 0);
        ret = qemu_strtou64(words[1], NULL, 0, &addr);
        g_assert(ret == 0);
        ret = qemu_strtou64(words[2], NULL, 0, &len);
        g_assert(ret == 0);
        /* We'd send garbage to libqtest if len is 0 */
        g_assert(len);

@@ -451,10 +464,13 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
        uint64_t addr, len;
        uint8_t *data;
        gchar *b64_data;
        int ret;

        g_assert(words[1] && words[2]);
        g_assert(qemu_strtou64(words[1], NULL, 0, &addr) == 0);
        g_assert(qemu_strtou64(words[2], NULL, 0, &len) == 0);
        ret = qemu_strtou64(words[1], NULL, 0, &addr);
        g_assert(ret == 0);
        ret = qemu_strtou64(words[2], NULL, 0, &len);
        g_assert(ret == 0);

        data = g_malloc(len);
        cpu_physical_memory_read(addr, data, len);
@@ -468,10 +484,13 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
        uint64_t addr, len, i;
        uint8_t *data;
        size_t data_len;
        int ret;

        g_assert(words[1] && words[2] && words[3]);
        g_assert(qemu_strtou64(words[1], NULL, 0, &addr) == 0);
        g_assert(qemu_strtou64(words[2], NULL, 0, &len) == 0);
        ret = qemu_strtou64(words[1], NULL, 0, &addr);
        g_assert(ret == 0);
        ret = qemu_strtou64(words[2], NULL, 0, &len);
        g_assert(ret == 0);

        data_len = strlen(words[3]);
        if (data_len < 3) {
@@ -497,11 +516,15 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
        uint64_t addr, len;
        uint8_t *data;
        unsigned long pattern;
        int ret;

        g_assert(words[1] && words[2] && words[3]);
        g_assert(qemu_strtou64(words[1], NULL, 0, &addr) == 0);
        g_assert(qemu_strtou64(words[2], NULL, 0, &len) == 0);
        g_assert(qemu_strtoul(words[3], NULL, 0, &pattern) == 0);
        ret = qemu_strtou64(words[1], NULL, 0, &addr);
        g_assert(ret == 0);
        ret = qemu_strtou64(words[2], NULL, 0, &len);
        g_assert(ret == 0);
        ret = qemu_strtoul(words[3], NULL, 0, &pattern);
        g_assert(ret == 0);

        if (len) {
            data = g_malloc(len);
@@ -517,10 +540,13 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
        uint8_t *data;
        size_t data_len;
        gsize out_len;
        int ret;

        g_assert(words[1] && words[2] && words[3]);
        g_assert(qemu_strtou64(words[1], NULL, 0, &addr) == 0);
        g_assert(qemu_strtou64(words[2], NULL, 0, &len) == 0);
        ret = qemu_strtou64(words[1], NULL, 0, &addr);
        g_assert(ret == 0);
        ret = qemu_strtou64(words[2], NULL, 0, &len);
        g_assert(ret == 0);

        data_len = strlen(words[3]);
        if (data_len < 3) {
@@ -551,11 +577,16 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
    } else if (strcmp(words[0], "rtas") == 0) {
        uint64_t res, args, ret;
        unsigned long nargs, nret;

        g_assert(qemu_strtoul(words[2], NULL, 0, &nargs) == 0);
        g_assert(qemu_strtou64(words[3], NULL, 0, &args) == 0);
        g_assert(qemu_strtoul(words[4], NULL, 0, &nret) == 0);
        g_assert(qemu_strtou64(words[5], NULL, 0, &ret) == 0);
        int rc;

        rc = qemu_strtoul(words[2], NULL, 0, &nargs);
        g_assert(rc == 0);
        rc = qemu_strtou64(words[3], NULL, 0, &args);
        g_assert(rc == 0);
        rc = qemu_strtoul(words[4], NULL, 0, &nret);
        g_assert(rc == 0);
        rc = qemu_strtou64(words[5], NULL, 0, &ret);
        g_assert(rc == 0);
        res = qtest_rtas_call(words[1], nargs, args, nret, ret);

        qtest_send_prefix(chr);
@@ -565,7 +596,8 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
        int64_t ns;

        if (words[1]) {
            g_assert(qemu_strtoi64(words[1], NULL, 0, &ns) == 0);
            int ret = qemu_strtoi64(words[1], NULL, 0, &ns);
            g_assert(ret == 0);
        } else {
            ns = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
        }
@@ -575,9 +607,11 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
                    (int64_t)qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
    } else if (qtest_enabled() && strcmp(words[0], "clock_set") == 0) {
        int64_t ns;
        int ret;

        g_assert(words[1]);
        g_assert(qemu_strtoi64(words[1], NULL, 0, &ns) == 0);
        ret = qemu_strtoi64(words[1], NULL, 0, &ns);
        g_assert(ret == 0);
        qtest_clock_warp(ns);
        qtest_send_prefix(chr);
        qtest_sendf(chr, "OK %"PRIi64"\n",
+8 −18
Original line number Diff line number Diff line
@@ -120,6 +120,8 @@ void qpci_msix_enable(QPCIDevice *dev)
    bir_pba = table & PCI_MSIX_FLAGS_BIRMASK;
    if (bir_pba != bir_table) {
        dev->msix_pba_bar = qpci_iomap(dev, bir_pba, NULL);
    } else {
        dev->msix_pba_bar = dev->msix_table_bar;
    }
    dev->msix_pba_off = table & ~PCI_MSIX_FLAGS_BIRMASK;

@@ -138,8 +140,11 @@ void qpci_msix_disable(QPCIDevice *dev)
    qpci_config_writew(dev, addr + PCI_MSIX_FLAGS,
                                                val & ~PCI_MSIX_FLAGS_ENABLE);

    qpci_iounmap(dev, dev->msix_table_bar);
    if (dev->msix_pba_bar.addr != dev->msix_table_bar.addr) {
        qpci_iounmap(dev, dev->msix_pba_bar);
    }
    qpci_iounmap(dev, dev->msix_table_bar);

    dev->msix_enabled = 0;
    dev->msix_table_off = 0;
    dev->msix_pba_off = 0;
@@ -394,21 +399,6 @@ QPCIBar qpci_legacy_iomap(QPCIDevice *dev, uint16_t addr)
void qpci_plug_device_test(const char *driver, const char *id,
                           uint8_t slot, const char *opts)
{
    QDict *response;
    char *cmd;

    cmd = g_strdup_printf("{'execute': 'device_add',"
                          " 'arguments': {"
                          "   'driver': '%s',"
                          "   'addr': '%d',"
                          "   %s%s"
                          "   'id': '%s'"
                          "}}", driver, slot,
                          opts ? opts : "", opts ? "," : "",
                          id);
    response = qmp(cmd);
    g_free(cmd);
    g_assert(response);
    g_assert(!qdict_haskey(response, "error"));
    QDECREF(response);
    qtest_qmp_device_add(driver, id, "'addr': '%d'%s%s", slot,
                         opts ? ", " : "", opts ? opts : "");
}
+6 −24
Original line number Diff line number Diff line
@@ -40,34 +40,16 @@ void uhci_port_test(struct qhc *hc, int port, uint16_t expect)
void usb_test_hotplug(const char *hcd_id, const int port,
                      void (*port_check)(void))
{
    QDict *response;
    char  *cmd;
    char  *id = g_strdup_printf("usbdev%d", port);

    cmd = g_strdup_printf("{'execute': 'device_add',"
                          " 'arguments': {"
                          "   'driver': 'usb-tablet',"
                          "   'port': '%d',"
                          "   'bus': '%s.0',"
                          "   'id': 'usbdev%d'"
                          "}}", port, hcd_id, port);
    response = qmp(cmd);
    g_free(cmd);
    g_assert(response);
    g_assert(!qdict_haskey(response, "error"));
    QDECREF(response);
    qtest_qmp_device_add("usb-tablet", id, "'port': '%d', 'bus': '%s.0'",
                         port, hcd_id);

    if (port_check) {
        port_check();
    }

    cmd = g_strdup_printf("{'execute': 'device_del',"
                           " 'arguments': {"
                           "   'id': 'usbdev%d'"
                           "}}", port);
    response = qmp(cmd);
    g_free(cmd);
    g_assert(response);
    g_assert(qdict_haskey(response, "event"));
    g_assert(!strcmp(qdict_get_str(response, "event"), "DEVICE_DELETED"));
    QDECREF(response);
    qtest_qmp_device_del(id);

    g_free(id);
}
+91 −14
Original line number Diff line number Diff line
@@ -42,7 +42,6 @@ struct QTestState
};

static GHookList abrt_hooks;
static GList *qtest_instances;
static struct sigaction sigact_old;

#define g_assert_no_errno(ret) do { \
@@ -150,6 +149,19 @@ void qtest_add_abrt_handler(GHookFunc fn, const void *data)
    g_hook_prepend(&abrt_hooks, hook);
}

static const char *qtest_qemu_binary(void)
{
    const char *qemu_bin;

    qemu_bin = getenv("QTEST_QEMU_BINARY");
    if (!qemu_bin) {
        fprintf(stderr, "Environment variable QTEST_QEMU_BINARY required\n");
        exit(1);
    }

    return qemu_bin;
}

QTestState *qtest_init_without_qmp_handshake(const char *extra_args)
{
    QTestState *s;
@@ -157,13 +169,7 @@ QTestState *qtest_init_without_qmp_handshake(const char *extra_args)
    gchar *socket_path;
    gchar *qmp_socket_path;
    gchar *command;
    const char *qemu_binary;

    qemu_binary = getenv("QTEST_QEMU_BINARY");
    if (!qemu_binary) {
        fprintf(stderr, "Environment variable QTEST_QEMU_BINARY required\n");
        exit(1);
    }
    const char *qemu_binary = qtest_qemu_binary();

    s = g_malloc(sizeof(*s));

@@ -240,13 +246,10 @@ QTestState *qtest_init(const char *extra_args)

void qtest_quit(QTestState *s)
{
    qtest_instances = g_list_remove(qtest_instances, s);
    g_hook_destroy_link(&abrt_hooks, g_hook_find_data(&abrt_hooks, TRUE, s));

    /* Uninstall SIGABRT handler on last instance */
    if (!qtest_instances) {
    cleanup_sigabrt_handler();
    }

    kill_qemu(s);
    close(s->fd);
@@ -624,8 +627,7 @@ char *qtest_hmp(QTestState *s, const char *fmt, ...)

const char *qtest_get_arch(void)
{
    const char *qemu = getenv("QTEST_QEMU_BINARY");
    g_assert(qemu != NULL);
    const char *qemu = qtest_qemu_binary();
    const char *end = strrchr(qemu, '/');

    return end + strlen("/qemu-system-");
@@ -987,3 +989,78 @@ void qtest_cb_for_every_machine(void (*cb)(const char *machine))
    qtest_end();
    QDECREF(response);
}

/*
 * Generic hot-plugging test via the device_add QMP command.
 */
void qtest_qmp_device_add(const char *driver, const char *id, const char *fmt,
                          ...)
{
    QDict *response;
    char *cmd, *opts = NULL;
    va_list va;

    if (fmt) {
        va_start(va, fmt);
        opts = g_strdup_vprintf(fmt, va);
        va_end(va);
    }

    cmd = g_strdup_printf("{'execute': 'device_add',"
                          " 'arguments': { 'driver': '%s', 'id': '%s'%s%s }}",
                          driver, id, opts ? ", " : "", opts ? opts : "");
    g_free(opts);

    response = qmp(cmd);
    g_free(cmd);
    g_assert(response);
    g_assert(!qdict_haskey(response, "event")); /* We don't expect any events */
    g_assert(!qdict_haskey(response, "error"));
    QDECREF(response);
}

/*
 * Generic hot-unplugging test via the device_del QMP command.
 * Device deletion will get one response and one event. For example:
 *
 * {'execute': 'device_del','arguments': { 'id': 'scsi-hd'}}
 *
 * will get this one:
 *
 * {"timestamp": {"seconds": 1505289667, "microseconds": 569862},
 *  "event": "DEVICE_DELETED", "data": {"device": "scsi-hd",
 *  "path": "/machine/peripheral/scsi-hd"}}
 *
 * and this one:
 *
 * {"return": {}}
 *
 * But the order of arrival may vary - so we've got to detect both.
 */
void qtest_qmp_device_del(const char *id)
{
    QDict *response1, *response2, *event = NULL;
    char *cmd;

    cmd = g_strdup_printf("{'execute': 'device_del',"
                          " 'arguments': { 'id': '%s' }}", id);
    response1 = qmp(cmd);
    g_free(cmd);
    g_assert(response1);
    g_assert(!qdict_haskey(response1, "error"));

    response2 = qmp("");
    g_assert(response2);
    g_assert(!qdict_haskey(response2, "error"));

    if (qdict_haskey(response1, "event")) {
        event = response1;
    } else if (qdict_haskey(response2, "event")) {
        event = response2;
    }
    g_assert(event);
    g_assert_cmpstr(qdict_get_str(event, "event"), ==, "DEVICE_DELETED");

    QDECREF(response1);
    QDECREF(response2);
}
+23 −4
Original line number Diff line number Diff line
@@ -134,14 +134,14 @@ QDict *qtest_qmp_eventwait_ref(QTestState *s, const char *event);
/**
 * qtest_hmp:
 * @s: #QTestState instance to operate on.
 * @fmt...: HMP command to send to QEMU
 * @fmt...: HMP command to send to QEMU, formats arguments like sprintf().
 *
 * Send HMP command to QEMU via QMP's human-monitor-command.
 * QMP events are discarded.
 *
 * Returns: the command's output.  The caller should g_free() it.
 */
char *qtest_hmp(QTestState *s, const char *fmt, ...);
char *qtest_hmp(QTestState *s, const char *fmt, ...) GCC_FMT_ATTR(2, 3);

/**
 * qtest_hmpv:
@@ -592,13 +592,13 @@ static inline QDict *qmp_eventwait_ref(const char *event)

/**
 * hmp:
 * @fmt...: HMP command to send to QEMU
 * @fmt...: HMP command to send to QEMU, formats arguments like sprintf().
 *
 * Send HMP command to QEMU via QMP's human-monitor-command.
 *
 * Returns: the command's output.  The caller should g_free() it.
 */
char *hmp(const char *fmt, ...);
char *hmp(const char *fmt, ...) GCC_FMT_ATTR(1, 2);

/**
 * get_irq:
@@ -927,4 +927,23 @@ QDict *qmp_fd(int fd, const char *fmt, ...);
 */
void qtest_cb_for_every_machine(void (*cb)(const char *machine));

/**
 * qtest_qmp_device_add:
 * @driver: Name of the device that should be added
 * @id: Identification string
 * @fmt: printf-like format string for further options to device_add
 *
 * Generic hot-plugging test via the device_add QMP command.
 */
void qtest_qmp_device_add(const char *driver, const char *id, const char *fmt,
                          ...) GCC_FMT_ATTR(3, 4);

/**
 * qtest_qmp_device_del:
 * @id: Identification string
 *
 * Generic hot-unplugging test via the device_del QMP command.
 */
void qtest_qmp_device_del(const char *id);

#endif
Loading