All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 1/2] qtest: add a few fd-level qmp helpers
@ 2015-08-27 10:52 marcandre.lureau
  2015-08-27 10:52 ` [Qemu-devel] [PATCH 2/2] tests: add a local test for guest agent marcandre.lureau
  2015-09-09 20:05 ` [Qemu-devel] [PATCH 1/2] qtest: add a few fd-level qmp helpers Michael Roth
  0 siblings, 2 replies; 7+ messages in thread
From: marcandre.lureau @ 2015-08-27 10:52 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, mdroth

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Add a few functions to interact with qmp via a simple fd.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 tests/libqtest.c | 45 +++++++++++++++++++++++++++++++++++++++++----
 tests/libqtest.h |  7 +++++++
 2 files changed, 48 insertions(+), 4 deletions(-)

diff --git a/tests/libqtest.c b/tests/libqtest.c
index e5188e0..11e541d 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -357,7 +357,7 @@ static void qmp_response(JSONMessageParser *parser, QList *tokens)
     qmp->response = (QDict *)obj;
 }
 
-QDict *qtest_qmp_receive(QTestState *s)
+QDict *qmp_fd_receive(int fd)
 {
     QMPResponseParser qmp;
     bool log = getenv("QTEST_LOG") != NULL;
@@ -368,7 +368,7 @@ QDict *qtest_qmp_receive(QTestState *s)
         ssize_t len;
         char c;
 
-        len = read(s->qmp_fd, &c, 1);
+        len = read(fd, &c, 1);
         if (len == -1 && errno == EINTR) {
             continue;
         }
@@ -388,12 +388,17 @@ QDict *qtest_qmp_receive(QTestState *s)
     return qmp.response;
 }
 
+QDict *qtest_qmp_receive(QTestState *s)
+{
+    return qmp_fd_receive(s->qmp_fd);
+}
+
 /**
  * Allow users to send a message without waiting for the reply,
  * in the case that they choose to discard all replies up until
  * a particular EVENT is received.
  */
-void qtest_async_qmpv(QTestState *s, const char *fmt, va_list ap)
+void qmp_fd_sendv(int fd, const char *fmt, va_list ap)
 {
     va_list ap_copy;
     QObject *qobj;
@@ -417,13 +422,25 @@ void qtest_async_qmpv(QTestState *s, const char *fmt, va_list ap)
             fprintf(stderr, "%s", str);
         }
         /* Send QMP request */
-        socket_send(s->qmp_fd, str, size);
+        socket_send(fd, str, size);
 
         QDECREF(qstr);
         qobject_decref(qobj);
     }
 }
 
+void qtest_async_qmpv(QTestState *s, const char *fmt, va_list ap)
+{
+    qmp_fd_sendv(s->qmp_fd, fmt, ap);
+}
+
+QDict *qmp_fdv(int fd, const char *fmt, va_list ap)
+{
+    qmp_fd_sendv(fd, fmt, ap);
+
+    return qmp_fd_receive(fd);
+}
+
 QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap)
 {
     qtest_async_qmpv(s, fmt, ap);
@@ -432,6 +449,26 @@ QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap)
     return qtest_qmp_receive(s);
 }
 
+QDict *qmp_fd(int fd, const char *fmt, ...)
+{
+    va_list ap;
+    QDict *response;
+
+    va_start(ap, fmt);
+    response = qmp_fdv(fd, fmt, ap);
+    va_end(ap);
+    return response;
+}
+
+void qmp_fd_send(int fd, const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    qmp_fd_sendv(fd, fmt, ap);
+    va_end(ap);
+}
+
 QDict *qtest_qmp(QTestState *s, const char *fmt, ...)
 {
     va_list ap;
diff --git a/tests/libqtest.h b/tests/libqtest.h
index ec42031..ecd9872 100644
--- a/tests/libqtest.h
+++ b/tests/libqtest.h
@@ -818,4 +818,11 @@ static inline int64_t clock_set(int64_t val)
  */
 bool qtest_big_endian(void);
 
+
+QDict *qmp_fd_receive(int fd);
+void qmp_fd_sendv(int fd, const char *fmt, va_list ap);
+void qmp_fd_send(int fd, const char *fmt, ...);
+QDict *qmp_fdv(int fd, const char *fmt, va_list ap);
+QDict *qmp_fd(int fd, const char *fmt, ...);
+
 #endif
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [Qemu-devel] [PATCH 2/2] tests: add a local test for guest agent
  2015-08-27 10:52 [Qemu-devel] [PATCH 1/2] qtest: add a few fd-level qmp helpers marcandre.lureau
@ 2015-08-27 10:52 ` marcandre.lureau
  2015-08-27 11:36   ` Marc-André Lureau
  2015-09-09 21:53   ` Michael Roth
  2015-09-09 20:05 ` [Qemu-devel] [PATCH 1/2] qtest: add a few fd-level qmp helpers Michael Roth
  1 sibling, 2 replies; 7+ messages in thread
From: marcandre.lureau @ 2015-08-27 10:52 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau, mdroth

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Add some local guest agent tests (as it is better than nothing).

They can be run inside or outside a VM, when run inside a VM, they will
do a bit more side effects, such as freezing/thawing the FS or changing
the time.

A better test would involve a managed VM (or container), but it might be
better to leave that off to autotest/avocado.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 tests/Makefile   |   3 +
 tests/test-qga.c | 686 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 689 insertions(+)
 create mode 100644 tests/test-qga.c

diff --git a/tests/Makefile b/tests/Makefile
index 5271123..35671a1 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -76,6 +76,7 @@ check-unit-y += tests/test-write-threshold$(EXESUF)
 gcov-files-test-write-threshold-y = block/write-threshold.c
 check-unit-$(CONFIG_GNUTLS_HASH) += tests/test-crypto-hash$(EXESUF)
 check-unit-y += tests/test-crypto-cipher$(EXESUF)
+check-unit-y += tests/test-qga$(EXESUF)
 
 check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
 
@@ -425,6 +426,8 @@ endif
 qtest-obj-y = tests/libqtest.o libqemuutil.a libqemustub.a
 $(check-qtest-y): $(qtest-obj-y)
 
+tests/test-qga: tests/test-qga.o $(qtest-obj-y)
+
 .PHONY: check-help
 check-help:
 	@echo "Regression testing targets:"
diff --git a/tests/test-qga.c b/tests/test-qga.c
new file mode 100644
index 0000000..1fb58ec
--- /dev/null
+++ b/tests/test-qga.c
@@ -0,0 +1,686 @@
+#include <locale.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "libqtest.h"
+#include "config-host.h"
+
+typedef struct {
+    char *test_dir;
+    GMainLoop *loop;
+    int fd;
+    GPid pid;
+} TestFixture;
+
+static int connect_qga(char *path)
+{
+    int s, ret, len;
+    struct sockaddr_un remote;
+
+    s = socket(AF_UNIX, SOCK_STREAM, 0);
+    g_assert(s != -1);
+
+    remote.sun_family = AF_UNIX;
+    do {
+        strcpy(remote.sun_path, path);
+        len = strlen(remote.sun_path) + sizeof(remote.sun_family);
+        ret = connect(s, (struct sockaddr *)&remote, len);
+        if (ret == -1) {
+            g_usleep(G_USEC_PER_SEC);
+        }
+    } while (ret == -1);
+
+    return s;
+}
+
+static void qga_watch(GPid pid, gint status, gpointer user_data)
+{
+    TestFixture *fixture = user_data;
+
+    g_assert_cmpint(status, ==, 0);
+    g_main_loop_quit(fixture->loop);
+}
+
+static void
+fixture_setup(TestFixture *fixture, gconstpointer data)
+{
+    const gchar *extra_arg = data;
+    GError *error = NULL;
+    gchar *cwd, *path, *cmd, **argv = NULL;
+
+    fixture->loop = g_main_loop_new(NULL, FALSE);
+
+    fixture->test_dir = g_strdup("/tmp/qgatest.XXXXXX");
+    g_assert_nonnull(g_mkdtemp(fixture->test_dir));
+
+    path = g_build_filename(fixture->test_dir, "sock", NULL);
+    cwd = g_get_current_dir();
+    cmd = g_strdup_printf("%s%cqemu-ga -m unix-listen -t %s -p %s %s %s",
+                          cwd, G_DIR_SEPARATOR,
+                          fixture->test_dir, path,
+                          getenv("QTEST_LOG") ? "-v" : "",
+                          extra_arg ?: "");
+    g_shell_parse_argv(cmd, NULL, &argv, &error);
+    g_assert_no_error(error);
+
+    g_spawn_async(fixture->test_dir, argv, NULL,
+                  G_SPAWN_SEARCH_PATH|G_SPAWN_DO_NOT_REAP_CHILD,
+                  NULL, NULL, &fixture->pid, &error);
+    g_assert_no_error(error);
+
+    g_child_watch_add(fixture->pid, qga_watch, fixture);
+
+    fixture->fd = connect_qga(path);
+
+    g_strfreev(argv);
+    g_free(cmd);
+    g_free(cwd);
+    g_free(path);
+}
+
+static void
+fixture_tear_down(TestFixture *fixture, gconstpointer data)
+{
+    gchar *tmp;
+
+    kill(fixture->pid, SIGTERM);
+
+    g_main_loop_run(fixture->loop);
+    g_main_loop_unref(fixture->loop);
+
+    g_spawn_close_pid(fixture->pid);
+
+    tmp = g_build_filename(fixture->test_dir, "foo", NULL);
+    g_unlink(tmp);
+    g_free(tmp);
+
+    tmp = g_build_filename(fixture->test_dir, "qga.state", NULL);
+    g_unlink(tmp);
+    g_free(tmp);
+
+    tmp = g_build_filename(fixture->test_dir, "sock", NULL);
+    g_unlink(tmp);
+    g_free(tmp);
+
+    g_rmdir(fixture->test_dir);
+    g_free(fixture->test_dir);
+}
+
+static void qmp_assertion_message_error(const char     *domain,
+                                        const char     *file,
+                                        int             line,
+                                        const char     *func,
+                                        const char     *expr,
+                                        QDict          *dict)
+{
+    const char *class, *desc;
+    char *s;
+    QDict *error;
+
+    error = qdict_get_qdict(dict, "error");
+    class = qdict_get_try_str(error, "class");
+    desc = qdict_get_try_str(error, "desc");
+
+    s = g_strdup_printf("assertion failed %s: %s %s", expr, class, desc);
+    g_assertion_message(domain, file, line, func, s);
+    g_free(s);
+}
+
+#define qmp_assert_no_error(err) do {                                   \
+    if (qdict_haskey(err, "error")) {                                   \
+        qmp_assertion_message_error(G_LOG_DOMAIN, __FILE__, __LINE__,   \
+                                    G_STRFUNC, #err, err);              \
+    }                                                                   \
+} while (0)
+
+static void test_qga_sync_delimited(gconstpointer fix)
+{
+    const TestFixture *fixture = fix;
+    guint32 v, r = g_random_int();
+    unsigned char c;
+    QDict *ret;
+    gchar *cmd;
+
+    cmd = g_strdup_printf("%c{'execute': 'guest-sync-delimited',"
+                          " 'arguments': {'id': %u } }", 0xff, r);
+    qmp_fd_send(fixture->fd, cmd);
+    g_free(cmd);
+
+    v = read(fixture->fd, &c, 1);
+    g_assert_cmpint(v, ==, 1);
+    g_assert_cmpint(c, ==, 0xff);
+
+    ret = qmp_fd_receive(fixture->fd);
+    g_assert_nonnull(ret);
+    qmp_assert_no_error(ret);
+
+    v = qdict_get_int(ret, "return");
+    g_assert_cmpint(r, ==, v);
+
+    QDECREF(ret);
+}
+
+static void test_qga_sync(gconstpointer fix)
+{
+    const TestFixture *fixture = fix;
+    guint32 v, r = g_random_int();
+    QDict *ret;
+    gchar *cmd;
+
+    cmd = g_strdup_printf("%c{'execute': 'guest-sync',"
+                          " 'arguments': {'id': %u } }", 0xff, r);
+    ret = qmp_fd(fixture->fd, cmd);
+    g_free(cmd);
+
+    g_assert_nonnull(ret);
+    qmp_assert_no_error(ret);
+
+    v = qdict_get_int(ret, "return");
+    g_assert_cmpint(r, ==, v);
+
+    QDECREF(ret);
+}
+
+static void test_qga_ping(gconstpointer fix)
+{
+    const TestFixture *fixture = fix;
+    QDict *ret;
+
+    ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping'}");
+    g_assert_nonnull(ret);
+    qmp_assert_no_error(ret);
+
+    QDECREF(ret);
+}
+
+static void test_qga_invalid_cmd(gconstpointer fix)
+{
+    const TestFixture *fixture = fix;
+    QDict *ret, *error;
+    const gchar *class, *desc;
+
+    ret = qmp_fd(fixture->fd, "{'execute': 'guest-invalid-cmd'}");
+    g_assert_nonnull(ret);
+
+    error = qdict_get_qdict(ret, "error");
+    class = qdict_get_try_str(error, "class");
+    desc = qdict_get_try_str(error, "desc");
+
+    g_assert_cmpstr(class, ==, "CommandNotFound");
+    g_assert_cmpint(strlen(desc), >, 0);
+
+    QDECREF(ret);
+}
+
+static void test_qga_info(gconstpointer fix)
+{
+    const TestFixture *fixture = fix;
+    QDict *ret, *val;
+    const gchar *version;
+
+    ret = qmp_fd(fixture->fd, "{'execute': 'guest-info'}");
+    g_assert_nonnull(ret);
+    qmp_assert_no_error(ret);
+
+    val = qdict_get_qdict(ret, "return");
+    version = qdict_get_try_str(val, "version");
+    g_assert_cmpstr(version, ==, QEMU_VERSION);
+
+    QDECREF(ret);
+}
+
+static void test_qga_get_vcpus(gconstpointer fix)
+{
+    const TestFixture *fixture = fix;
+    QDict *ret;
+    QList *list;
+    const QListEntry *entry;
+
+    ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-vcpus'}");
+    g_assert_nonnull(ret);
+    qmp_assert_no_error(ret);
+
+    /* check there is at least a cpu */
+    list = qdict_get_qlist(ret, "return");
+    entry = qlist_first(list);
+    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "online"));
+    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "logical-id"));
+
+    QDECREF(ret);
+}
+
+static void test_qga_get_fsinfo(gconstpointer fix)
+{
+    const TestFixture *fixture = fix;
+    QDict *ret;
+    QList *list;
+    const QListEntry *entry;
+
+    ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-fsinfo'}");
+    g_assert_nonnull(ret);
+    qmp_assert_no_error(ret);
+
+    /* check there is at least a fs */
+    list = qdict_get_qlist(ret, "return");
+    entry = qlist_first(list);
+    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "name"));
+    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "mountpoint"));
+    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "type"));
+    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "disk"));
+
+    QDECREF(ret);
+}
+
+static void test_qga_get_memory_block_info(gconstpointer fix)
+{
+    const TestFixture *fixture = fix;
+    QDict *ret, *val;
+    int64_t size;
+
+    ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-memory-block-info'}");
+    g_assert_nonnull(ret);
+    qmp_assert_no_error(ret);
+
+    /* check there is at least some memory */
+    val = qdict_get_qdict(ret, "return");
+    size = qdict_get_int(val, "size");
+    g_assert_cmpint(size, >, 0);
+
+    QDECREF(ret);
+}
+
+static void test_qga_get_memory_blocks(gconstpointer fix)
+{
+    const TestFixture *fixture = fix;
+    QDict *ret;
+    QList *list;
+    const QListEntry *entry;
+
+    ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-memory-blocks'}");
+    g_assert_nonnull(ret);
+    qmp_assert_no_error(ret);
+
+    list = qdict_get_qlist(ret, "return");
+    entry = qlist_first(list);
+    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "phys-index"));
+    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "online"));
+
+    QDECREF(ret);
+}
+
+static void test_qga_network_get_interfaces(gconstpointer fix)
+{
+    const TestFixture *fixture = fix;
+    QDict *ret;
+    QList *list;
+    const QListEntry *entry;
+
+    ret = qmp_fd(fixture->fd, "{'execute': 'guest-network-get-interfaces'}");
+    g_assert_nonnull(ret);
+    qmp_assert_no_error(ret);
+
+    /* check there is at least a cpu */
+    list = qdict_get_qlist(ret, "return");
+    entry = qlist_first(list);
+    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "name"));
+
+    QDECREF(ret);
+}
+
+static void test_qga_file_ops(gconstpointer fix)
+{
+    const TestFixture *fixture = fix;
+    gchar *cmd, *path;
+    const gchar *b64;
+    QDict *ret, *val;
+    int64_t id, count, eof;
+    FILE *f;
+    char tmp[100];
+
+    /* open */
+    ret = qmp_fd(fixture->fd, "{'execute': 'guest-file-open',"
+                 " 'arguments': { 'path': 'foo', 'mode': 'w+' } }");
+    g_assert_nonnull(ret);
+    qmp_assert_no_error(ret);
+    id = qdict_get_int(ret, "return");
+    QDECREF(ret);
+
+    /* write */
+    cmd = g_strdup_printf("{'execute': 'guest-file-write',"
+                          " 'arguments': { 'handle': %" G_GINT64_FORMAT ","
+                          " 'buf-b64': 'aGVsbG8gd29ybGQK' } }", id);
+    ret = qmp_fd(fixture->fd, cmd);
+    g_assert_nonnull(ret);
+    qmp_assert_no_error(ret);
+
+    val = qdict_get_qdict(ret, "return");
+    count = qdict_get_int(val, "count");
+    eof = qdict_get_bool(val, "eof");
+    g_assert_cmpint(count, ==, 12);
+    g_assert_cmpint(eof, ==, 0);
+    QDECREF(ret);
+    g_free(cmd);
+
+    /* flush */
+    cmd = g_strdup_printf("{'execute': 'guest-file-flush',"
+                          " 'arguments': {'handle': %" G_GINT64_FORMAT "} }",
+                          id);
+    ret = qmp_fd(fixture->fd, cmd);
+    QDECREF(ret);
+    g_free(cmd);
+
+    /* close */
+    cmd = g_strdup_printf("{'execute': 'guest-file-close',"
+                          " 'arguments': {'handle': %" G_GINT64_FORMAT "} }",
+                          id);
+    ret = qmp_fd(fixture->fd, cmd);
+    QDECREF(ret);
+    g_free(cmd);
+
+    /* check content */
+    path = g_build_filename(fixture->test_dir, "foo", NULL);
+    f = fopen(path, "r");
+    g_assert_nonnull(f);
+    count = fread(tmp, 1, sizeof(tmp), f);
+    g_assert_cmpint(count, ==, 12);
+    tmp[count] = 0;
+    g_assert_cmpstr(tmp, ==, "hello world\n");
+    fclose(f);
+
+    /* open */
+    ret = qmp_fd(fixture->fd, "{'execute': 'guest-file-open',"
+                 " 'arguments': { 'path': 'foo', 'mode': 'r' } }");
+    g_assert_nonnull(ret);
+    qmp_assert_no_error(ret);
+    id = qdict_get_int(ret, "return");
+    QDECREF(ret);
+
+    /* read */
+    cmd = g_strdup_printf("{'execute': 'guest-file-read',"
+                          " 'arguments': { 'handle': %" G_GINT64_FORMAT "} }",
+                          id);
+    ret = qmp_fd(fixture->fd, cmd);
+    val = qdict_get_qdict(ret, "return");
+    count = qdict_get_int(val, "count");
+    eof = qdict_get_bool(val, "eof");
+    b64 = qdict_get_str(val, "buf-b64");
+    g_assert_cmpint(count, ==, 12);
+    g_assert(eof);
+    g_assert_cmpstr(b64, ==, "aGVsbG8gd29ybGQK");
+
+    QDECREF(ret);
+    g_free(cmd);
+
+    /* read eof */
+    cmd = g_strdup_printf("{'execute': 'guest-file-read',"
+                          " 'arguments': { 'handle': %" G_GINT64_FORMAT "} }",
+                          id);
+    ret = qmp_fd(fixture->fd, cmd);
+    val = qdict_get_qdict(ret, "return");
+    count = qdict_get_int(val, "count");
+    eof = qdict_get_bool(val, "eof");
+    b64 = qdict_get_str(val, "buf-b64");
+    g_assert_cmpint(count, ==, 0);
+    g_assert(eof);
+    g_assert_cmpstr(b64, ==, "");
+    QDECREF(ret);
+    g_free(cmd);
+
+    /* seek */
+    cmd = g_strdup_printf("{'execute': 'guest-file-seek',"
+                          " 'arguments': { 'handle': %" G_GINT64_FORMAT ", "
+                          " 'offset': %d, 'whence': %d } }",
+                          id, 6, SEEK_SET);
+    ret = qmp_fd(fixture->fd, cmd);
+    qmp_assert_no_error(ret);
+    val = qdict_get_qdict(ret, "return");
+    count = qdict_get_int(val, "position");
+    eof = qdict_get_bool(val, "eof");
+    g_assert_cmpint(count, ==, 6);
+    g_assert(!eof);
+    QDECREF(ret);
+    g_free(cmd);
+
+    /* partial read */
+    cmd = g_strdup_printf("{'execute': 'guest-file-read',"
+                          " 'arguments': { 'handle': %" G_GINT64_FORMAT "} }",
+                          id);
+    ret = qmp_fd(fixture->fd, cmd);
+    val = qdict_get_qdict(ret, "return");
+    count = qdict_get_int(val, "count");
+    eof = qdict_get_bool(val, "eof");
+    b64 = qdict_get_str(val, "buf-b64");
+    g_assert_cmpint(count, ==, 6);
+    g_assert(eof);
+    g_assert_cmpstr(b64, ==, "d29ybGQK");
+
+    QDECREF(ret);
+    g_free(cmd);
+
+    /* close */
+    cmd = g_strdup_printf("{'execute': 'guest-file-close',"
+                          " 'arguments': {'handle': %" G_GINT64_FORMAT "} }",
+                          id);
+    ret = qmp_fd(fixture->fd, cmd);
+    QDECREF(ret);
+    g_free(cmd);
+}
+
+static void test_qga_get_time(gconstpointer fix)
+{
+    const TestFixture *fixture = fix;
+    QDict *ret;
+    int64_t time;
+
+    ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-time'}");
+    g_assert_nonnull(ret);
+    qmp_assert_no_error(ret);
+
+    time = qdict_get_int(ret, "return");
+    g_assert_cmpint(time, >, 0);
+
+    QDECREF(ret);
+}
+
+static void test_qga_set_time(gconstpointer fix)
+{
+    const TestFixture *fixture = fix;
+    QDict *ret;
+    int64_t current, time;
+    gchar *cmd;
+
+    /* get current time */
+    ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-time'}");
+    g_assert_nonnull(ret);
+    qmp_assert_no_error(ret);
+    current = qdict_get_int(ret, "return");
+    g_assert_cmpint(current, >, 0);
+    QDECREF(ret);
+
+    /* set some old time */
+    ret = qmp_fd(fixture->fd, "{'execute': 'guest-set-time',"
+                 " 'arguments': { 'time': 1000 } }");
+    g_assert_nonnull(ret);
+    qmp_assert_no_error(ret);
+    QDECREF(ret);
+
+    /* check old time */
+    ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-time'}");
+    g_assert_nonnull(ret);
+    qmp_assert_no_error(ret);
+    time = qdict_get_int(ret, "return");
+    g_assert_cmpint(time / 1000, <, G_USEC_PER_SEC * 10);
+    QDECREF(ret);
+
+    /* set back current time */
+    cmd = g_strdup_printf("{'execute': 'guest-set-time',"
+                          " 'arguments': { 'time': %" G_GINT64_FORMAT " } }",
+                          current + time * 1000);
+    ret = qmp_fd(fixture->fd, cmd);
+    g_free(cmd);
+    g_assert_nonnull(ret);
+    qmp_assert_no_error(ret);
+    QDECREF(ret);
+}
+
+static void test_qga_fstrim(gconstpointer fix)
+{
+    const TestFixture *fixture = fix;
+    QDict *ret;
+    QList *list;
+    const QListEntry *entry;
+
+    /* get current time */
+    ret = qmp_fd(fixture->fd, "{'execute': 'guest-fstrim',"
+                 " arguments: { minimum: 4194304 } }");
+    g_assert_nonnull(ret);
+    qmp_assert_no_error(ret);
+    list = qdict_get_qlist(ret, "return");
+    entry = qlist_first(list);
+    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "paths"));
+
+    QDECREF(ret);
+}
+
+static void test_qga_blacklist(gconstpointer data)
+{
+    TestFixture fix;
+    QDict *ret, *error;
+    const gchar *class, *desc;
+
+    fixture_setup(&fix, "-b guest-ping,guest-get-time");
+
+    /* check blacklist */
+    ret = qmp_fd(fix.fd, "{'execute': 'guest-ping'}");
+    g_assert_nonnull(ret);
+    error = qdict_get_qdict(ret, "error");
+    class = qdict_get_try_str(error, "class");
+    desc = qdict_get_try_str(error, "desc");
+    g_assert_cmpstr(class, ==, "GenericError");
+    g_assert_nonnull(g_strstr_len(desc, -1, "has been disabled"));
+    QDECREF(ret);
+
+    ret = qmp_fd(fix.fd, "{'execute': 'guest-get-time'}");
+    g_assert_nonnull(ret);
+    error = qdict_get_qdict(ret, "error");
+    class = qdict_get_try_str(error, "class");
+    desc = qdict_get_try_str(error, "desc");
+    g_assert_cmpstr(class, ==, "GenericError");
+    g_assert_nonnull(g_strstr_len(desc, -1, "has been disabled"));
+    QDECREF(ret);
+
+    /* check something work */
+    ret = qmp_fd(fix.fd, "{'execute': 'guest-get-fsinfo'}");
+    qmp_assert_no_error(ret);
+    QDECREF(ret);
+
+    fixture_tear_down(&fix, NULL);
+}
+
+static void test_qga_fsfreeze_status(gconstpointer fix)
+{
+    const TestFixture *fixture = fix;
+    QDict *ret;
+    const gchar *status;
+
+    ret = qmp_fd(fixture->fd, "{'execute': 'guest-fsfreeze-status'}");
+    g_assert_nonnull(ret);
+    qmp_assert_no_error(ret);
+
+    status = qdict_get_try_str(ret, "return");
+    g_assert_cmpstr(status, ==, "thawed");
+
+    QDECREF(ret);
+}
+
+static void test_qga_fsfreeze_and_thaw(gconstpointer fix)
+{
+    const TestFixture *fixture = fix;
+    QDict *ret;
+    const gchar *status;
+
+    ret = qmp_fd(fixture->fd, "{'execute': 'guest-fsfreeze-freeze'}");
+    g_assert_nonnull(ret);
+    qmp_assert_no_error(ret);
+    QDECREF(ret);
+
+    ret = qmp_fd(fixture->fd, "{'execute': 'guest-fsfreeze-status'}");
+    g_assert_nonnull(ret);
+    qmp_assert_no_error(ret);
+    status = qdict_get_try_str(ret, "return");
+    g_assert_cmpstr(status, ==, "frozen");
+    QDECREF(ret);
+
+    ret = qmp_fd(fixture->fd, "{'execute': 'guest-fsfreeze-thaw'}");
+    g_assert_nonnull(ret);
+    qmp_assert_no_error(ret);
+    QDECREF(ret);
+}
+
+static gboolean running_in_virt(const gchar *virt)
+{
+    gchar *virt_what = NULL;
+    gint status;
+    gboolean success;
+
+    success = g_spawn_command_line_sync("virt-what", &virt_what, NULL,
+                                        &status, NULL);
+
+    success = success && status == 0 && g_strcmp0(virt_what, virt);
+
+    g_free(virt_what);
+
+    return success;
+}
+int main(int argc, char **argv)
+{
+    TestFixture fix;
+    int ret;
+
+    setlocale (LC_ALL, "");
+    g_test_init(&argc, &argv, NULL);
+    fixture_setup(&fix, NULL);
+
+    g_test_add_data_func("/qga/sync-delimited", &fix, test_qga_sync_delimited);
+    g_test_add_data_func("/qga/sync", &fix, test_qga_sync);
+    g_test_add_data_func("/qga/ping", &fix, test_qga_ping);
+    g_test_add_data_func("/qga/info", &fix, test_qga_info);
+    g_test_add_data_func("/qga/network-get-interfaces", &fix,
+                         test_qga_network_get_interfaces);
+    g_test_add_data_func("/qga/get-vcpus", &fix, test_qga_get_vcpus);
+    g_test_add_data_func("/qga/get-fsinfo", &fix, test_qga_get_fsinfo);
+    g_test_add_data_func("/qga/get-memory-block-info", &fix,
+                         test_qga_get_memory_block_info);
+    g_test_add_data_func("/qga/get-memory-blocks", &fix,
+                         test_qga_get_memory_blocks);
+    g_test_add_data_func("/qga/file-ops", &fix, test_qga_file_ops);
+    g_test_add_data_func("/qga/get-time", &fix, test_qga_get_time);
+    g_test_add_data_func("/qga/invalid-cmd", &fix, test_qga_invalid_cmd);
+    g_test_add_data_func("/qga/fsfreeze-status", &fix,
+                         test_qga_fsfreeze_status);
+
+    g_test_add_data_func("/qga/blacklist", NULL, test_qga_blacklist);
+
+    if (running_in_virt("kvm")) {
+        g_test_add_data_func("/qga/fsfreeze-and-thaw", &fix,
+                             test_qga_fsfreeze_and_thaw);
+        g_test_add_data_func("/qga/set-time", &fix, test_qga_set_time);
+        if (g_test_thorough()) {
+            g_test_add_data_func("/qga/fstrim", &fix, test_qga_fstrim);
+        }
+    }
+
+    ret = g_test_run();
+
+    fixture_tear_down(&fix, NULL);
+
+    return ret;
+}
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [Qemu-devel] [PATCH 2/2] tests: add a local test for guest agent
  2015-08-27 10:52 ` [Qemu-devel] [PATCH 2/2] tests: add a local test for guest agent marcandre.lureau
@ 2015-08-27 11:36   ` Marc-André Lureau
  2015-09-09 17:36     ` Michael Roth
  2015-09-09 21:53   ` Michael Roth
  1 sibling, 1 reply; 7+ messages in thread
From: Marc-André Lureau @ 2015-08-27 11:36 UTC (permalink / raw)
  To: QEMU; +Cc: Marc-André Lureau, Michael Roth

On Thu, Aug 27, 2015 at 12:52 PM,  <marcandre.lureau@redhat.com> wrote:
> +    success = success && status == 0 && g_strcmp0(virt_what, virt);

this is now:
g_strcmp0(g_strstrip(virt_what), virt) == 0

-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Qemu-devel] [PATCH 2/2] tests: add a local test for guest agent
  2015-08-27 11:36   ` Marc-André Lureau
@ 2015-09-09 17:36     ` Michael Roth
  0 siblings, 0 replies; 7+ messages in thread
From: Michael Roth @ 2015-09-09 17:36 UTC (permalink / raw)
  To: Marc-André Lureau, QEMU; +Cc: Marc-André Lureau

Quoting Marc-André Lureau (2015-08-27 06:36:43)
> On Thu, Aug 27, 2015 at 12:52 PM,  <marcandre.lureau@redhat.com> wrote:
> > +    success = success && status == 0 && g_strcmp0(virt_what, virt);
> 
> this is now:
> g_strcmp0(g_strstrip(virt_what), virt) == 0

Just to be sure, is this the change you intended?

diff --git a/tests/test-qga.c b/tests/test-qga.c
index 1fb58ec..ca4bcb5 100644
--- a/tests/test-qga.c
+++ b/tests/test-qga.c
@@ -634,7 +634,8 @@ static gboolean running_in_virt(const gchar *virt)
     success = g_spawn_command_line_sync("virt-what", &virt_what, NULL,
                                         &status, NULL);
 
-    success = success && status == 0 && g_strcmp0(virt_what, virt);
+    success = success && status == 0 &&
+        g_strcmp0(g_strstrip(virt_what), virt) == 0;
 
     g_free(virt_what);

> 
> -- 
> Marc-André Lureau
> 

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [Qemu-devel] [PATCH 1/2] qtest: add a few fd-level qmp helpers
  2015-08-27 10:52 [Qemu-devel] [PATCH 1/2] qtest: add a few fd-level qmp helpers marcandre.lureau
  2015-08-27 10:52 ` [Qemu-devel] [PATCH 2/2] tests: add a local test for guest agent marcandre.lureau
@ 2015-09-09 20:05 ` Michael Roth
  1 sibling, 0 replies; 7+ messages in thread
From: Michael Roth @ 2015-09-09 20:05 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel

Quoting marcandre.lureau@redhat.com (2015-08-27 05:52:06)
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> Add a few functions to interact with qmp via a simple fd.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

Reviewed-by: Michael Roth <mdroth@linux.vnet.ibm.com>

> ---
>  tests/libqtest.c | 45 +++++++++++++++++++++++++++++++++++++++++----
>  tests/libqtest.h |  7 +++++++
>  2 files changed, 48 insertions(+), 4 deletions(-)
> 
> diff --git a/tests/libqtest.c b/tests/libqtest.c
> index e5188e0..11e541d 100644
> --- a/tests/libqtest.c
> +++ b/tests/libqtest.c
> @@ -357,7 +357,7 @@ static void qmp_response(JSONMessageParser *parser, QList *tokens)
>      qmp->response = (QDict *)obj;
>  }
> 
> -QDict *qtest_qmp_receive(QTestState *s)
> +QDict *qmp_fd_receive(int fd)
>  {
>      QMPResponseParser qmp;
>      bool log = getenv("QTEST_LOG") != NULL;
> @@ -368,7 +368,7 @@ QDict *qtest_qmp_receive(QTestState *s)
>          ssize_t len;
>          char c;
> 
> -        len = read(s->qmp_fd, &c, 1);
> +        len = read(fd, &c, 1);
>          if (len == -1 && errno == EINTR) {
>              continue;
>          }
> @@ -388,12 +388,17 @@ QDict *qtest_qmp_receive(QTestState *s)
>      return qmp.response;
>  }
> 
> +QDict *qtest_qmp_receive(QTestState *s)
> +{
> +    return qmp_fd_receive(s->qmp_fd);
> +}
> +
>  /**
>   * Allow users to send a message without waiting for the reply,
>   * in the case that they choose to discard all replies up until
>   * a particular EVENT is received.
>   */
> -void qtest_async_qmpv(QTestState *s, const char *fmt, va_list ap)
> +void qmp_fd_sendv(int fd, const char *fmt, va_list ap)
>  {
>      va_list ap_copy;
>      QObject *qobj;
> @@ -417,13 +422,25 @@ void qtest_async_qmpv(QTestState *s, const char *fmt, va_list ap)
>              fprintf(stderr, "%s", str);
>          }
>          /* Send QMP request */
> -        socket_send(s->qmp_fd, str, size);
> +        socket_send(fd, str, size);
> 
>          QDECREF(qstr);
>          qobject_decref(qobj);
>      }
>  }
> 
> +void qtest_async_qmpv(QTestState *s, const char *fmt, va_list ap)
> +{
> +    qmp_fd_sendv(s->qmp_fd, fmt, ap);
> +}
> +
> +QDict *qmp_fdv(int fd, const char *fmt, va_list ap)
> +{
> +    qmp_fd_sendv(fd, fmt, ap);
> +
> +    return qmp_fd_receive(fd);
> +}
> +
>  QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap)
>  {
>      qtest_async_qmpv(s, fmt, ap);
> @@ -432,6 +449,26 @@ QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap)
>      return qtest_qmp_receive(s);
>  }
> 
> +QDict *qmp_fd(int fd, const char *fmt, ...)
> +{
> +    va_list ap;
> +    QDict *response;
> +
> +    va_start(ap, fmt);
> +    response = qmp_fdv(fd, fmt, ap);
> +    va_end(ap);
> +    return response;
> +}
> +
> +void qmp_fd_send(int fd, const char *fmt, ...)
> +{
> +    va_list ap;
> +
> +    va_start(ap, fmt);
> +    qmp_fd_sendv(fd, fmt, ap);
> +    va_end(ap);
> +}
> +
>  QDict *qtest_qmp(QTestState *s, const char *fmt, ...)
>  {
>      va_list ap;
> diff --git a/tests/libqtest.h b/tests/libqtest.h
> index ec42031..ecd9872 100644
> --- a/tests/libqtest.h
> +++ b/tests/libqtest.h
> @@ -818,4 +818,11 @@ static inline int64_t clock_set(int64_t val)
>   */
>  bool qtest_big_endian(void);
> 
> +
> +QDict *qmp_fd_receive(int fd);
> +void qmp_fd_sendv(int fd, const char *fmt, va_list ap);
> +void qmp_fd_send(int fd, const char *fmt, ...);
> +QDict *qmp_fdv(int fd, const char *fmt, va_list ap);
> +QDict *qmp_fd(int fd, const char *fmt, ...);
> +
>  #endif
> -- 
> 2.4.3
> 
> 

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Qemu-devel] [PATCH 2/2] tests: add a local test for guest agent
  2015-08-27 10:52 ` [Qemu-devel] [PATCH 2/2] tests: add a local test for guest agent marcandre.lureau
  2015-08-27 11:36   ` Marc-André Lureau
@ 2015-09-09 21:53   ` Michael Roth
  2015-09-11 17:46     ` Marc-André Lureau
  1 sibling, 1 reply; 7+ messages in thread
From: Michael Roth @ 2015-09-09 21:53 UTC (permalink / raw)
  To: marcandre.lureau, qemu-devel

Quoting marcandre.lureau@redhat.com (2015-08-27 05:52:07)
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> Add some local guest agent tests (as it is better than nothing).
> 
> They can be run inside or outside a VM, when run inside a VM, they will
> do a bit more side effects, such as freezing/thawing the FS or changing
> the time.
> 
> A better test would involve a managed VM (or container), but it might be
> better to leave that off to autotest/avocado.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  tests/Makefile   |   3 +
>  tests/test-qga.c | 686 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 689 insertions(+)
>  create mode 100644 tests/test-qga.c
> 
> diff --git a/tests/Makefile b/tests/Makefile
> index 5271123..35671a1 100644
> --- a/tests/Makefile
> +++ b/tests/Makefile
> @@ -76,6 +76,7 @@ check-unit-y += tests/test-write-threshold$(EXESUF)
>  gcov-files-test-write-threshold-y = block/write-threshold.c
>  check-unit-$(CONFIG_GNUTLS_HASH) += tests/test-crypto-hash$(EXESUF)
>  check-unit-y += tests/test-crypto-cipher$(EXESUF)
> +check-unit-y += tests/test-qga$(EXESUF)
> 
>  check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
> 
> @@ -425,6 +426,8 @@ endif
>  qtest-obj-y = tests/libqtest.o libqemuutil.a libqemustub.a
>  $(check-qtest-y): $(qtest-obj-y)
> 
> +tests/test-qga: tests/test-qga.o $(qtest-obj-y)
> +
>  .PHONY: check-help
>  check-help:
>         @echo "Regression testing targets:"
> diff --git a/tests/test-qga.c b/tests/test-qga.c
> new file mode 100644
> index 0000000..1fb58ec
> --- /dev/null
> +++ b/tests/test-qga.c
> @@ -0,0 +1,686 @@
> +#include <locale.h>
> +#include <glib.h>
> +#include <glib/gstdio.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <errno.h>
> +#include <string.h>
> +#include <sys/types.h>
> +#include <sys/socket.h>
> +#include <sys/un.h>
> +#include <unistd.h>
> +
> +#include "libqtest.h"
> +#include "config-host.h"
> +
> +typedef struct {
> +    char *test_dir;
> +    GMainLoop *loop;
> +    int fd;
> +    GPid pid;
> +} TestFixture;
> +
> +static int connect_qga(char *path)
> +{
> +    int s, ret, len;
> +    struct sockaddr_un remote;
> +
> +    s = socket(AF_UNIX, SOCK_STREAM, 0);
> +    g_assert(s != -1);
> +
> +    remote.sun_family = AF_UNIX;
> +    do {
> +        strcpy(remote.sun_path, path);
> +        len = strlen(remote.sun_path) + sizeof(remote.sun_family);
> +        ret = connect(s, (struct sockaddr *)&remote, len);
> +        if (ret == -1) {
> +            g_usleep(G_USEC_PER_SEC);
> +        }
> +    } while (ret == -1);

I think we should loop on ECONNREFUSED (or whatever corresponds to
the socket not yet being created/bound), and the usual suspects
like EINTR. If it's anything else I don't think we'd want this to
loop indefinitely.

> +
> +    return s;
> +}
> +
> +static void qga_watch(GPid pid, gint status, gpointer user_data)
> +{
> +    TestFixture *fixture = user_data;
> +
> +    g_assert_cmpint(status, ==, 0);
> +    g_main_loop_quit(fixture->loop);
> +}
> +
> +static void
> +fixture_setup(TestFixture *fixture, gconstpointer data)
> +{
> +    const gchar *extra_arg = data;
> +    GError *error = NULL;
> +    gchar *cwd, *path, *cmd, **argv = NULL;
> +
> +    fixture->loop = g_main_loop_new(NULL, FALSE);
> +
> +    fixture->test_dir = g_strdup("/tmp/qgatest.XXXXXX");
> +    g_assert_nonnull(g_mkdtemp(fixture->test_dir));
> +
> +    path = g_build_filename(fixture->test_dir, "sock", NULL);
> +    cwd = g_get_current_dir();
> +    cmd = g_strdup_printf("%s%cqemu-ga -m unix-listen -t %s -p %s %s %s",

Would be nice if we could also run qemu-ga.exe for a w32 build with
binfmt set up like some of the other tests, but no idea how we'd get
at it through wine. I guess it would have to be a serial connection
or something...

Probably too environment-specific for a useful unit test. I guess in
the future we could plumb in custom qemu-ga invocation/script that
does some extra setup on the backend (VM/container/wine) and exposes
that via a local socket like we'd get via -chardev.

> +                          cwd, G_DIR_SEPARATOR,
> +                          fixture->test_dir, path,
> +                          getenv("QTEST_LOG") ? "-v" : "",
> +                          extra_arg ?: "");
> +    g_shell_parse_argv(cmd, NULL, &argv, &error);
> +    g_assert_no_error(error);
> +
> +    g_spawn_async(fixture->test_dir, argv, NULL,
> +                  G_SPAWN_SEARCH_PATH|G_SPAWN_DO_NOT_REAP_CHILD,
> +                  NULL, NULL, &fixture->pid, &error);
> +    g_assert_no_error(error);
> +
> +    g_child_watch_add(fixture->pid, qga_watch, fixture);
> +
> +    fixture->fd = connect_qga(path);
> +
> +    g_strfreev(argv);
> +    g_free(cmd);
> +    g_free(cwd);
> +    g_free(path);
> +}
> +
> +static void
> +fixture_tear_down(TestFixture *fixture, gconstpointer data)
> +{
> +    gchar *tmp;
> +
> +    kill(fixture->pid, SIGTERM);
> +
> +    g_main_loop_run(fixture->loop);
> +    g_main_loop_unref(fixture->loop);
> +
> +    g_spawn_close_pid(fixture->pid);
> +
> +    tmp = g_build_filename(fixture->test_dir, "foo", NULL);
> +    g_unlink(tmp);
> +    g_free(tmp);

Shouldn't the individual unit tests clean these up? I think a flag
determining whether or not we're running locally (set by default
obviously) would be useful for determining whether it makes sense
for us to clean them up or not.

> +
> +    tmp = g_build_filename(fixture->test_dir, "qga.state", NULL);
> +    g_unlink(tmp);
> +    g_free(tmp);
> +
> +    tmp = g_build_filename(fixture->test_dir, "sock", NULL);
> +    g_unlink(tmp);
> +    g_free(tmp);
> +
> +    g_rmdir(fixture->test_dir);
> +    g_free(fixture->test_dir);
> +}
> +
> +static void qmp_assertion_message_error(const char     *domain,
> +                                        const char     *file,
> +                                        int             line,
> +                                        const char     *func,
> +                                        const char     *expr,
> +                                        QDict          *dict)
> +{
> +    const char *class, *desc;
> +    char *s;
> +    QDict *error;
> +
> +    error = qdict_get_qdict(dict, "error");
> +    class = qdict_get_try_str(error, "class");
> +    desc = qdict_get_try_str(error, "desc");
> +
> +    s = g_strdup_printf("assertion failed %s: %s %s", expr, class, desc);
> +    g_assertion_message(domain, file, line, func, s);
> +    g_free(s);
> +}
> +
> +#define qmp_assert_no_error(err) do {                                   \
> +    if (qdict_haskey(err, "error")) {                                   \
> +        qmp_assertion_message_error(G_LOG_DOMAIN, __FILE__, __LINE__,   \
> +                                    G_STRFUNC, #err, err);              \
> +    }                                                                   \
> +} while (0)
> +
> +static void test_qga_sync_delimited(gconstpointer fix)
> +{
> +    const TestFixture *fixture = fix;
> +    guint32 v, r = g_random_int();
> +    unsigned char c;
> +    QDict *ret;
> +    gchar *cmd;
> +
> +    cmd = g_strdup_printf("%c{'execute': 'guest-sync-delimited',"
> +                          " 'arguments': {'id': %u } }", 0xff, r);
> +    qmp_fd_send(fixture->fd, cmd);
> +    g_free(cmd);
> +
> +    v = read(fixture->fd, &c, 1);
> +    g_assert_cmpint(v, ==, 1);
> +    g_assert_cmpint(c, ==, 0xff);
> +
> +    ret = qmp_fd_receive(fixture->fd);
> +    g_assert_nonnull(ret);
> +    qmp_assert_no_error(ret);
> +
> +    v = qdict_get_int(ret, "return");
> +    g_assert_cmpint(r, ==, v);
> +
> +    QDECREF(ret);
> +}
> +
> +static void test_qga_sync(gconstpointer fix)
> +{
> +    const TestFixture *fixture = fix;
> +    guint32 v, r = g_random_int();
> +    QDict *ret;
> +    gchar *cmd;
> +
> +    cmd = g_strdup_printf("%c{'execute': 'guest-sync',"
> +                          " 'arguments': {'id': %u } }", 0xff, r);
> +    ret = qmp_fd(fixture->fd, cmd);
> +    g_free(cmd);
> +
> +    g_assert_nonnull(ret);
> +    qmp_assert_no_error(ret);
> +
> +    v = qdict_get_int(ret, "return");
> +    g_assert_cmpint(r, ==, v);
> +
> +    QDECREF(ret);
> +}
> +
> +static void test_qga_ping(gconstpointer fix)
> +{
> +    const TestFixture *fixture = fix;
> +    QDict *ret;
> +
> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping'}");
> +    g_assert_nonnull(ret);
> +    qmp_assert_no_error(ret);
> +
> +    QDECREF(ret);
> +}
> +
> +static void test_qga_invalid_cmd(gconstpointer fix)
> +{
> +    const TestFixture *fixture = fix;
> +    QDict *ret, *error;
> +    const gchar *class, *desc;
> +
> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-invalid-cmd'}");
> +    g_assert_nonnull(ret);
> +
> +    error = qdict_get_qdict(ret, "error");
> +    class = qdict_get_try_str(error, "class");
> +    desc = qdict_get_try_str(error, "desc");
> +
> +    g_assert_cmpstr(class, ==, "CommandNotFound");
> +    g_assert_cmpint(strlen(desc), >, 0);
> +
> +    QDECREF(ret);
> +}
> +
> +static void test_qga_info(gconstpointer fix)
> +{
> +    const TestFixture *fixture = fix;
> +    QDict *ret, *val;
> +    const gchar *version;
> +
> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-info'}");
> +    g_assert_nonnull(ret);
> +    qmp_assert_no_error(ret);
> +
> +    val = qdict_get_qdict(ret, "return");
> +    version = qdict_get_try_str(val, "version");
> +    g_assert_cmpstr(version, ==, QEMU_VERSION);
> +
> +    QDECREF(ret);
> +}
> +
> +static void test_qga_get_vcpus(gconstpointer fix)
> +{
> +    const TestFixture *fixture = fix;
> +    QDict *ret;
> +    QList *list;
> +    const QListEntry *entry;
> +
> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-vcpus'}");
> +    g_assert_nonnull(ret);
> +    qmp_assert_no_error(ret);
> +
> +    /* check there is at least a cpu */
> +    list = qdict_get_qlist(ret, "return");
> +    entry = qlist_first(list);
> +    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "online"));
> +    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "logical-id"));
> +
> +    QDECREF(ret);
> +}
> +
> +static void test_qga_get_fsinfo(gconstpointer fix)
> +{
> +    const TestFixture *fixture = fix;
> +    QDict *ret;
> +    QList *list;
> +    const QListEntry *entry;
> +
> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-fsinfo'}");
> +    g_assert_nonnull(ret);
> +    qmp_assert_no_error(ret);
> +
> +    /* check there is at least a fs */
> +    list = qdict_get_qlist(ret, "return");
> +    entry = qlist_first(list);
> +    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "name"));
> +    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "mountpoint"));
> +    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "type"));
> +    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "disk"));
> +
> +    QDECREF(ret);
> +}
> +
> +static void test_qga_get_memory_block_info(gconstpointer fix)
> +{
> +    const TestFixture *fixture = fix;
> +    QDict *ret, *val;
> +    int64_t size;
> +
> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-memory-block-info'}");
> +    g_assert_nonnull(ret);
> +    qmp_assert_no_error(ret);
> +
> +    /* check there is at least some memory */
> +    val = qdict_get_qdict(ret, "return");
> +    size = qdict_get_int(val, "size");
> +    g_assert_cmpint(size, >, 0);
> +
> +    QDECREF(ret);
> +}
> +
> +static void test_qga_get_memory_blocks(gconstpointer fix)
> +{
> +    const TestFixture *fixture = fix;
> +    QDict *ret;
> +    QList *list;
> +    const QListEntry *entry;
> +
> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-memory-blocks'}");
> +    g_assert_nonnull(ret);
> +    qmp_assert_no_error(ret);
> +
> +    list = qdict_get_qlist(ret, "return");
> +    entry = qlist_first(list);
> +    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "phys-index"));
> +    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "online"));
> +
> +    QDECREF(ret);
> +}
> +
> +static void test_qga_network_get_interfaces(gconstpointer fix)
> +{
> +    const TestFixture *fixture = fix;
> +    QDict *ret;
> +    QList *list;
> +    const QListEntry *entry;
> +
> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-network-get-interfaces'}");
> +    g_assert_nonnull(ret);
> +    qmp_assert_no_error(ret);
> +
> +    /* check there is at least a cpu */

copy/paste artifact

> +    list = qdict_get_qlist(ret, "return");
> +    entry = qlist_first(list);
> +    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "name"));
> +
> +    QDECREF(ret);
> +}
> +
> +static void test_qga_file_ops(gconstpointer fix)
> +{
> +    const TestFixture *fixture = fix;
> +    gchar *cmd, *path;
> +    const gchar *b64;
> +    QDict *ret, *val;
> +    int64_t id, count, eof;
> +    FILE *f;
> +    char tmp[100];
> +
> +    /* open */
> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-file-open',"
> +                 " 'arguments': { 'path': 'foo', 'mode': 'w+' } }");
> +    g_assert_nonnull(ret);
> +    qmp_assert_no_error(ret);
> +    id = qdict_get_int(ret, "return");
> +    QDECREF(ret);
> +
> +    /* write */
> +    cmd = g_strdup_printf("{'execute': 'guest-file-write',"
> +                          " 'arguments': { 'handle': %" G_GINT64_FORMAT ","
> +                          " 'buf-b64': 'aGVsbG8gd29ybGQK' } }", id);
> +    ret = qmp_fd(fixture->fd, cmd);
> +    g_assert_nonnull(ret);
> +    qmp_assert_no_error(ret);
> +
> +    val = qdict_get_qdict(ret, "return");
> +    count = qdict_get_int(val, "count");
> +    eof = qdict_get_bool(val, "eof");
> +    g_assert_cmpint(count, ==, 12);
> +    g_assert_cmpint(eof, ==, 0);
> +    QDECREF(ret);
> +    g_free(cmd);
> +
> +    /* flush */
> +    cmd = g_strdup_printf("{'execute': 'guest-file-flush',"
> +                          " 'arguments': {'handle': %" G_GINT64_FORMAT "} }",
> +                          id);
> +    ret = qmp_fd(fixture->fd, cmd);
> +    QDECREF(ret);
> +    g_free(cmd);
> +
> +    /* close */
> +    cmd = g_strdup_printf("{'execute': 'guest-file-close',"
> +                          " 'arguments': {'handle': %" G_GINT64_FORMAT "} }",
> +                          id);
> +    ret = qmp_fd(fixture->fd, cmd);
> +    QDECREF(ret);
> +    g_free(cmd);
> +
> +    /* check content */
> +    path = g_build_filename(fixture->test_dir, "foo", NULL);
> +    f = fopen(path, "r");
> +    g_assert_nonnull(f);
> +    count = fread(tmp, 1, sizeof(tmp), f);
> +    g_assert_cmpint(count, ==, 12);
> +    tmp[count] = 0;
> +    g_assert_cmpstr(tmp, ==, "hello world\n");
> +    fclose(f);
> +
> +    /* open */
> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-file-open',"
> +                 " 'arguments': { 'path': 'foo', 'mode': 'r' } }");
> +    g_assert_nonnull(ret);
> +    qmp_assert_no_error(ret);
> +    id = qdict_get_int(ret, "return");
> +    QDECREF(ret);
> +
> +    /* read */
> +    cmd = g_strdup_printf("{'execute': 'guest-file-read',"
> +                          " 'arguments': { 'handle': %" G_GINT64_FORMAT "} }",
> +                          id);
> +    ret = qmp_fd(fixture->fd, cmd);
> +    val = qdict_get_qdict(ret, "return");
> +    count = qdict_get_int(val, "count");
> +    eof = qdict_get_bool(val, "eof");
> +    b64 = qdict_get_str(val, "buf-b64");
> +    g_assert_cmpint(count, ==, 12);
> +    g_assert(eof);
> +    g_assert_cmpstr(b64, ==, "aGVsbG8gd29ybGQK");
> +
> +    QDECREF(ret);
> +    g_free(cmd);
> +
> +    /* read eof */
> +    cmd = g_strdup_printf("{'execute': 'guest-file-read',"
> +                          " 'arguments': { 'handle': %" G_GINT64_FORMAT "} }",
> +                          id);
> +    ret = qmp_fd(fixture->fd, cmd);
> +    val = qdict_get_qdict(ret, "return");
> +    count = qdict_get_int(val, "count");
> +    eof = qdict_get_bool(val, "eof");
> +    b64 = qdict_get_str(val, "buf-b64");
> +    g_assert_cmpint(count, ==, 0);
> +    g_assert(eof);
> +    g_assert_cmpstr(b64, ==, "");
> +    QDECREF(ret);
> +    g_free(cmd);
> +
> +    /* seek */
> +    cmd = g_strdup_printf("{'execute': 'guest-file-seek',"
> +                          " 'arguments': { 'handle': %" G_GINT64_FORMAT ", "
> +                          " 'offset': %d, 'whence': %d } }",
> +                          id, 6, SEEK_SET);
> +    ret = qmp_fd(fixture->fd, cmd);
> +    qmp_assert_no_error(ret);
> +    val = qdict_get_qdict(ret, "return");
> +    count = qdict_get_int(val, "position");
> +    eof = qdict_get_bool(val, "eof");
> +    g_assert_cmpint(count, ==, 6);
> +    g_assert(!eof);
> +    QDECREF(ret);
> +    g_free(cmd);
> +
> +    /* partial read */
> +    cmd = g_strdup_printf("{'execute': 'guest-file-read',"
> +                          " 'arguments': { 'handle': %" G_GINT64_FORMAT "} }",
> +                          id);
> +    ret = qmp_fd(fixture->fd, cmd);
> +    val = qdict_get_qdict(ret, "return");
> +    count = qdict_get_int(val, "count");
> +    eof = qdict_get_bool(val, "eof");
> +    b64 = qdict_get_str(val, "buf-b64");
> +    g_assert_cmpint(count, ==, 6);
> +    g_assert(eof);
> +    g_assert_cmpstr(b64, ==, "d29ybGQK");
> +
> +    QDECREF(ret);
> +    g_free(cmd);
> +
> +    /* close */
> +    cmd = g_strdup_printf("{'execute': 'guest-file-close',"
> +                          " 'arguments': {'handle': %" G_GINT64_FORMAT "} }",
> +                          id);
> +    ret = qmp_fd(fixture->fd, cmd);

I like having a complex test to make sure all the guest-file-* commands
interact properly, but would be good if we could preceed this with
simpler guest-file-* tests that test each command more granularly.

That could be added as a follow-up though, since this is still a good
test to have.

> +    QDECREF(ret);
> +    g_free(cmd);
> +}
> +
> +static void test_qga_get_time(gconstpointer fix)
> +{
> +    const TestFixture *fixture = fix;
> +    QDict *ret;
> +    int64_t time;
> +
> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-time'}");
> +    g_assert_nonnull(ret);
> +    qmp_assert_no_error(ret);
> +
> +    time = qdict_get_int(ret, "return");
> +    g_assert_cmpint(time, >, 0);
> +
> +    QDECREF(ret);
> +}
> +
> +static void test_qga_set_time(gconstpointer fix)
> +{
> +    const TestFixture *fixture = fix;
> +    QDict *ret;
> +    int64_t current, time;
> +    gchar *cmd;
> +
> +    /* get current time */
> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-time'}");
> +    g_assert_nonnull(ret);
> +    qmp_assert_no_error(ret);
> +    current = qdict_get_int(ret, "return");
> +    g_assert_cmpint(current, >, 0);
> +    QDECREF(ret);
> +
> +    /* set some old time */
> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-set-time',"
> +                 " 'arguments': { 'time': 1000 } }");
> +    g_assert_nonnull(ret);
> +    qmp_assert_no_error(ret);
> +    QDECREF(ret);
> +
> +    /* check old time */
> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-time'}");
> +    g_assert_nonnull(ret);
> +    qmp_assert_no_error(ret);
> +    time = qdict_get_int(ret, "return");
> +    g_assert_cmpint(time / 1000, <, G_USEC_PER_SEC * 10);
> +    QDECREF(ret);
> +
> +    /* set back current time */
> +    cmd = g_strdup_printf("{'execute': 'guest-set-time',"
> +                          " 'arguments': { 'time': %" G_GINT64_FORMAT " } }",
> +                          current + time * 1000);
> +    ret = qmp_fd(fixture->fd, cmd);

Little concerned about playing with host time in our unit tests. Maybe
this sort of test should only be enabled if a flag is set, and turned
of by default?

Ah, I see that's where running_in_virt() comes into play. Nice :)

> +    g_free(cmd);
> +    g_assert_nonnull(ret);
> +    qmp_assert_no_error(ret);
> +    QDECREF(ret);
> +}
> +
> +static void test_qga_fstrim(gconstpointer fix)
> +{
> +    const TestFixture *fixture = fix;
> +    QDict *ret;
> +    QList *list;
> +    const QListEntry *entry;
> +
> +    /* get current time */

copy/paste artifact

> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-fstrim',"
> +                 " arguments: { minimum: 4194304 } }");
> +    g_assert_nonnull(ret);
> +    qmp_assert_no_error(ret);
> +    list = qdict_get_qlist(ret, "return");
> +    entry = qlist_first(list);
> +    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "paths"));
> +
> +    QDECREF(ret);
> +}
> +
> +static void test_qga_blacklist(gconstpointer data)
> +{
> +    TestFixture fix;
> +    QDict *ret, *error;
> +    const gchar *class, *desc;
> +
> +    fixture_setup(&fix, "-b guest-ping,guest-get-time");
> +
> +    /* check blacklist */
> +    ret = qmp_fd(fix.fd, "{'execute': 'guest-ping'}");
> +    g_assert_nonnull(ret);
> +    error = qdict_get_qdict(ret, "error");
> +    class = qdict_get_try_str(error, "class");
> +    desc = qdict_get_try_str(error, "desc");
> +    g_assert_cmpstr(class, ==, "GenericError");
> +    g_assert_nonnull(g_strstr_len(desc, -1, "has been disabled"));
> +    QDECREF(ret);
> +
> +    ret = qmp_fd(fix.fd, "{'execute': 'guest-get-time'}");
> +    g_assert_nonnull(ret);
> +    error = qdict_get_qdict(ret, "error");
> +    class = qdict_get_try_str(error, "class");
> +    desc = qdict_get_try_str(error, "desc");
> +    g_assert_cmpstr(class, ==, "GenericError");
> +    g_assert_nonnull(g_strstr_len(desc, -1, "has been disabled"));
> +    QDECREF(ret);
> +
> +    /* check something work */
> +    ret = qmp_fd(fix.fd, "{'execute': 'guest-get-fsinfo'}");
> +    qmp_assert_no_error(ret);
> +    QDECREF(ret);
> +
> +    fixture_tear_down(&fix, NULL);
> +}
> +
> +static void test_qga_fsfreeze_status(gconstpointer fix)
> +{
> +    const TestFixture *fixture = fix;
> +    QDict *ret;
> +    const gchar *status;
> +
> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-fsfreeze-status'}");
> +    g_assert_nonnull(ret);
> +    qmp_assert_no_error(ret);
> +
> +    status = qdict_get_try_str(ret, "return");
> +    g_assert_cmpstr(status, ==, "thawed");
> +
> +    QDECREF(ret);
> +}
> +
> +static void test_qga_fsfreeze_and_thaw(gconstpointer fix)
> +{
> +    const TestFixture *fixture = fix;
> +    QDict *ret;
> +    const gchar *status;
> +
> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-fsfreeze-freeze'}");
> +    g_assert_nonnull(ret);
> +    qmp_assert_no_error(ret);
> +    QDECREF(ret);
> +
> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-fsfreeze-status'}");
> +    g_assert_nonnull(ret);
> +    qmp_assert_no_error(ret);
> +    status = qdict_get_try_str(ret, "return");
> +    g_assert_cmpstr(status, ==, "frozen");
> +    QDECREF(ret);
> +
> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-fsfreeze-thaw'}");
> +    g_assert_nonnull(ret);
> +    qmp_assert_no_error(ret);
> +    QDECREF(ret);
> +}
> +
> +static gboolean running_in_virt(const gchar *virt)
> +{
> +    gchar *virt_what = NULL;
> +    gint status;
> +    gboolean success;
> +
> +    success = g_spawn_command_line_sync("virt-what", &virt_what, NULL,
> +                                        &status, NULL);
> +
> +    success = success && status == 0 && g_strcmp0(virt_what, virt);
> +
> +    g_free(virt_what);
> +
> +    return success;
> +}
> +int main(int argc, char **argv)
> +{
> +    TestFixture fix;
> +    int ret;
> +
> +    setlocale (LC_ALL, "");
> +    g_test_init(&argc, &argv, NULL);
> +    fixture_setup(&fix, NULL);
> +
> +    g_test_add_data_func("/qga/sync-delimited", &fix, test_qga_sync_delimited);
> +    g_test_add_data_func("/qga/sync", &fix, test_qga_sync);
> +    g_test_add_data_func("/qga/ping", &fix, test_qga_ping);
> +    g_test_add_data_func("/qga/info", &fix, test_qga_info);
> +    g_test_add_data_func("/qga/network-get-interfaces", &fix,
> +                         test_qga_network_get_interfaces);
> +    g_test_add_data_func("/qga/get-vcpus", &fix, test_qga_get_vcpus);
> +    g_test_add_data_func("/qga/get-fsinfo", &fix, test_qga_get_fsinfo);
> +    g_test_add_data_func("/qga/get-memory-block-info", &fix,
> +                         test_qga_get_memory_block_info);
> +    g_test_add_data_func("/qga/get-memory-blocks", &fix,
> +                         test_qga_get_memory_blocks);
> +    g_test_add_data_func("/qga/file-ops", &fix, test_qga_file_ops);
> +    g_test_add_data_func("/qga/get-time", &fix, test_qga_get_time);
> +    g_test_add_data_func("/qga/invalid-cmd", &fix, test_qga_invalid_cmd);
> +    g_test_add_data_func("/qga/fsfreeze-status", &fix,
> +                         test_qga_fsfreeze_status);
> +
> +    g_test_add_data_func("/qga/blacklist", NULL, test_qga_blacklist);
> +
> +    if (running_in_virt("kvm")) {
> +        g_test_add_data_func("/qga/fsfreeze-and-thaw", &fix,
> +                             test_qga_fsfreeze_and_thaw);
> +        g_test_add_data_func("/qga/set-time", &fix, test_qga_set_time);
> +        if (g_test_thorough()) {
> +            g_test_add_data_func("/qga/fstrim", &fix, test_qga_fstrim);
> +        }
> +    }
> +
> +    ret = g_test_run();
> +
> +    fixture_tear_down(&fix, NULL);
> +
> +    return ret;
> +}
> -- 
> 2.4.3
> 

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Qemu-devel] [PATCH 2/2] tests: add a local test for guest agent
  2015-09-09 21:53   ` Michael Roth
@ 2015-09-11 17:46     ` Marc-André Lureau
  0 siblings, 0 replies; 7+ messages in thread
From: Marc-André Lureau @ 2015-09-11 17:46 UTC (permalink / raw)
  To: Michael Roth; +Cc: QEMU

Hi

On Wed, Sep 9, 2015 at 11:53 PM, Michael Roth <mdroth@linux.vnet.ibm.com> wrote:
> Quoting marcandre.lureau@redhat.com (2015-08-27 05:52:07)
>> From: Marc-André Lureau <marcandre.lureau@redhat.com>
>>
>> Add some local guest agent tests (as it is better than nothing).
>>
>> They can be run inside or outside a VM, when run inside a VM, they will
>> do a bit more side effects, such as freezing/thawing the FS or changing
>> the time.
>>
>> A better test would involve a managed VM (or container), but it might be
>> better to leave that off to autotest/avocado.
>>
>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>> ---
>>  tests/Makefile   |   3 +
>>  tests/test-qga.c | 686 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 689 insertions(+)
>>  create mode 100644 tests/test-qga.c
>>
>> diff --git a/tests/Makefile b/tests/Makefile
>> index 5271123..35671a1 100644
>> --- a/tests/Makefile
>> +++ b/tests/Makefile
>> @@ -76,6 +76,7 @@ check-unit-y += tests/test-write-threshold$(EXESUF)
>>  gcov-files-test-write-threshold-y = block/write-threshold.c
>>  check-unit-$(CONFIG_GNUTLS_HASH) += tests/test-crypto-hash$(EXESUF)
>>  check-unit-y += tests/test-crypto-cipher$(EXESUF)
>> +check-unit-y += tests/test-qga$(EXESUF)
>>
>>  check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
>>
>> @@ -425,6 +426,8 @@ endif
>>  qtest-obj-y = tests/libqtest.o libqemuutil.a libqemustub.a
>>  $(check-qtest-y): $(qtest-obj-y)
>>
>> +tests/test-qga: tests/test-qga.o $(qtest-obj-y)
>> +
>>  .PHONY: check-help
>>  check-help:
>>         @echo "Regression testing targets:"
>> diff --git a/tests/test-qga.c b/tests/test-qga.c
>> new file mode 100644
>> index 0000000..1fb58ec
>> --- /dev/null
>> +++ b/tests/test-qga.c
>> @@ -0,0 +1,686 @@
>> +#include <locale.h>
>> +#include <glib.h>
>> +#include <glib/gstdio.h>
>> +#include <stdio.h>
>> +#include <stdlib.h>
>> +#include <errno.h>
>> +#include <string.h>
>> +#include <sys/types.h>
>> +#include <sys/socket.h>
>> +#include <sys/un.h>
>> +#include <unistd.h>
>> +
>> +#include "libqtest.h"
>> +#include "config-host.h"
>> +
>> +typedef struct {
>> +    char *test_dir;
>> +    GMainLoop *loop;
>> +    int fd;
>> +    GPid pid;
>> +} TestFixture;
>> +
>> +static int connect_qga(char *path)
>> +{
>> +    int s, ret, len;
>> +    struct sockaddr_un remote;
>> +
>> +    s = socket(AF_UNIX, SOCK_STREAM, 0);
>> +    g_assert(s != -1);
>> +
>> +    remote.sun_family = AF_UNIX;
>> +    do {
>> +        strcpy(remote.sun_path, path);
>> +        len = strlen(remote.sun_path) + sizeof(remote.sun_family);
>> +        ret = connect(s, (struct sockaddr *)&remote, len);
>> +        if (ret == -1) {
>> +            g_usleep(G_USEC_PER_SEC);
>> +        }
>> +    } while (ret == -1);
>
> I think we should loop on ECONNREFUSED (or whatever corresponds to
> the socket not yet being created/bound), and the usual suspects
> like EINTR. If it's anything else I don't think we'd want this to
> loop indefinitely.

You get ENOENT while qga starts. I will just give up after 5 tries instead.

>> +
>> +    return s;
>> +}
>> +
>> +static void qga_watch(GPid pid, gint status, gpointer user_data)
>> +{
>> +    TestFixture *fixture = user_data;
>> +
>> +    g_assert_cmpint(status, ==, 0);
>> +    g_main_loop_quit(fixture->loop);
>> +}
>> +
>> +static void
>> +fixture_setup(TestFixture *fixture, gconstpointer data)
>> +{
>> +    const gchar *extra_arg = data;
>> +    GError *error = NULL;
>> +    gchar *cwd, *path, *cmd, **argv = NULL;
>> +
>> +    fixture->loop = g_main_loop_new(NULL, FALSE);
>> +
>> +    fixture->test_dir = g_strdup("/tmp/qgatest.XXXXXX");
>> +    g_assert_nonnull(g_mkdtemp(fixture->test_dir));
>> +
>> +    path = g_build_filename(fixture->test_dir, "sock", NULL);
>> +    cwd = g_get_current_dir();
>> +    cmd = g_strdup_printf("%s%cqemu-ga -m unix-listen -t %s -p %s %s %s",
>
> Would be nice if we could also run qemu-ga.exe for a w32 build with
> binfmt set up like some of the other tests, but no idea how we'd get
> at it through wine. I guess it would have to be a serial connection
> or something...
>
> Probably too environment-specific for a useful unit test. I guess in
> the future we could plumb in custom qemu-ga invocation/script that
> does some extra setup on the backend (VM/container/wine) and exposes
> that via a local socket like we'd get via -chardev.

Perhaps it would be just too much at this point for a make check test,
better to leave that to autotest etc.

At this point, I propose we make it check-unit-$(CONFIG_LINUX).

>
>> +                          cwd, G_DIR_SEPARATOR,
>> +                          fixture->test_dir, path,
>> +                          getenv("QTEST_LOG") ? "-v" : "",
>> +                          extra_arg ?: "");
>> +    g_shell_parse_argv(cmd, NULL, &argv, &error);
>> +    g_assert_no_error(error);
>> +
>> +    g_spawn_async(fixture->test_dir, argv, NULL,
>> +                  G_SPAWN_SEARCH_PATH|G_SPAWN_DO_NOT_REAP_CHILD,
>> +                  NULL, NULL, &fixture->pid, &error);
>> +    g_assert_no_error(error);
>> +
>> +    g_child_watch_add(fixture->pid, qga_watch, fixture);
>> +
>> +    fixture->fd = connect_qga(path);
>> +
>> +    g_strfreev(argv);
>> +    g_free(cmd);
>> +    g_free(cwd);
>> +    g_free(path);
>> +}
>> +
>> +static void
>> +fixture_tear_down(TestFixture *fixture, gconstpointer data)
>> +{
>> +    gchar *tmp;
>> +
>> +    kill(fixture->pid, SIGTERM);
>> +
>> +    g_main_loop_run(fixture->loop);
>> +    g_main_loop_unref(fixture->loop);
>> +
>> +    g_spawn_close_pid(fixture->pid);
>> +
>> +    tmp = g_build_filename(fixture->test_dir, "foo", NULL);
>> +    g_unlink(tmp);
>> +    g_free(tmp);
>
> Shouldn't the individual unit tests clean these up? I think a flag
> determining whether or not we're running locally (set by default
> obviously) would be useful for determining whether it makes sense
> for us to clean them up or not.

I started writing tests using test_add(), so qga would be started for
each tests, but the overhead was unnecessary. So it's just final
cleanup now.

>
>> +
>> +    tmp = g_build_filename(fixture->test_dir, "qga.state", NULL);
>> +    g_unlink(tmp);
>> +    g_free(tmp);
>> +
>> +    tmp = g_build_filename(fixture->test_dir, "sock", NULL);
>> +    g_unlink(tmp);
>> +    g_free(tmp);
>> +
>> +    g_rmdir(fixture->test_dir);
>> +    g_free(fixture->test_dir);
>> +}
>> +
>> +static void qmp_assertion_message_error(const char     *domain,
>> +                                        const char     *file,
>> +                                        int             line,
>> +                                        const char     *func,
>> +                                        const char     *expr,
>> +                                        QDict          *dict)
>> +{
>> +    const char *class, *desc;
>> +    char *s;
>> +    QDict *error;
>> +
>> +    error = qdict_get_qdict(dict, "error");
>> +    class = qdict_get_try_str(error, "class");
>> +    desc = qdict_get_try_str(error, "desc");
>> +
>> +    s = g_strdup_printf("assertion failed %s: %s %s", expr, class, desc);
>> +    g_assertion_message(domain, file, line, func, s);
>> +    g_free(s);
>> +}
>> +
>> +#define qmp_assert_no_error(err) do {                                   \
>> +    if (qdict_haskey(err, "error")) {                                   \
>> +        qmp_assertion_message_error(G_LOG_DOMAIN, __FILE__, __LINE__,   \
>> +                                    G_STRFUNC, #err, err);              \
>> +    }                                                                   \
>> +} while (0)
>> +
>> +static void test_qga_sync_delimited(gconstpointer fix)
>> +{
>> +    const TestFixture *fixture = fix;
>> +    guint32 v, r = g_random_int();
>> +    unsigned char c;
>> +    QDict *ret;
>> +    gchar *cmd;
>> +
>> +    cmd = g_strdup_printf("%c{'execute': 'guest-sync-delimited',"
>> +                          " 'arguments': {'id': %u } }", 0xff, r);
>> +    qmp_fd_send(fixture->fd, cmd);
>> +    g_free(cmd);
>> +
>> +    v = read(fixture->fd, &c, 1);
>> +    g_assert_cmpint(v, ==, 1);
>> +    g_assert_cmpint(c, ==, 0xff);
>> +
>> +    ret = qmp_fd_receive(fixture->fd);
>> +    g_assert_nonnull(ret);
>> +    qmp_assert_no_error(ret);
>> +
>> +    v = qdict_get_int(ret, "return");
>> +    g_assert_cmpint(r, ==, v);
>> +
>> +    QDECREF(ret);
>> +}
>> +
>> +static void test_qga_sync(gconstpointer fix)
>> +{
>> +    const TestFixture *fixture = fix;
>> +    guint32 v, r = g_random_int();
>> +    QDict *ret;
>> +    gchar *cmd;
>> +
>> +    cmd = g_strdup_printf("%c{'execute': 'guest-sync',"
>> +                          " 'arguments': {'id': %u } }", 0xff, r);
>> +    ret = qmp_fd(fixture->fd, cmd);
>> +    g_free(cmd);
>> +
>> +    g_assert_nonnull(ret);
>> +    qmp_assert_no_error(ret);
>> +
>> +    v = qdict_get_int(ret, "return");
>> +    g_assert_cmpint(r, ==, v);
>> +
>> +    QDECREF(ret);
>> +}
>> +
>> +static void test_qga_ping(gconstpointer fix)
>> +{
>> +    const TestFixture *fixture = fix;
>> +    QDict *ret;
>> +
>> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping'}");
>> +    g_assert_nonnull(ret);
>> +    qmp_assert_no_error(ret);
>> +
>> +    QDECREF(ret);
>> +}
>> +
>> +static void test_qga_invalid_cmd(gconstpointer fix)
>> +{
>> +    const TestFixture *fixture = fix;
>> +    QDict *ret, *error;
>> +    const gchar *class, *desc;
>> +
>> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-invalid-cmd'}");
>> +    g_assert_nonnull(ret);
>> +
>> +    error = qdict_get_qdict(ret, "error");
>> +    class = qdict_get_try_str(error, "class");
>> +    desc = qdict_get_try_str(error, "desc");
>> +
>> +    g_assert_cmpstr(class, ==, "CommandNotFound");
>> +    g_assert_cmpint(strlen(desc), >, 0);
>> +
>> +    QDECREF(ret);
>> +}
>> +
>> +static void test_qga_info(gconstpointer fix)
>> +{
>> +    const TestFixture *fixture = fix;
>> +    QDict *ret, *val;
>> +    const gchar *version;
>> +
>> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-info'}");
>> +    g_assert_nonnull(ret);
>> +    qmp_assert_no_error(ret);
>> +
>> +    val = qdict_get_qdict(ret, "return");
>> +    version = qdict_get_try_str(val, "version");
>> +    g_assert_cmpstr(version, ==, QEMU_VERSION);
>> +
>> +    QDECREF(ret);
>> +}
>> +
>> +static void test_qga_get_vcpus(gconstpointer fix)
>> +{
>> +    const TestFixture *fixture = fix;
>> +    QDict *ret;
>> +    QList *list;
>> +    const QListEntry *entry;
>> +
>> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-vcpus'}");
>> +    g_assert_nonnull(ret);
>> +    qmp_assert_no_error(ret);
>> +
>> +    /* check there is at least a cpu */
>> +    list = qdict_get_qlist(ret, "return");
>> +    entry = qlist_first(list);
>> +    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "online"));
>> +    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "logical-id"));
>> +
>> +    QDECREF(ret);
>> +}
>> +
>> +static void test_qga_get_fsinfo(gconstpointer fix)
>> +{
>> +    const TestFixture *fixture = fix;
>> +    QDict *ret;
>> +    QList *list;
>> +    const QListEntry *entry;
>> +
>> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-fsinfo'}");
>> +    g_assert_nonnull(ret);
>> +    qmp_assert_no_error(ret);
>> +
>> +    /* check there is at least a fs */
>> +    list = qdict_get_qlist(ret, "return");
>> +    entry = qlist_first(list);
>> +    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "name"));
>> +    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "mountpoint"));
>> +    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "type"));
>> +    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "disk"));
>> +
>> +    QDECREF(ret);
>> +}
>> +
>> +static void test_qga_get_memory_block_info(gconstpointer fix)
>> +{
>> +    const TestFixture *fixture = fix;
>> +    QDict *ret, *val;
>> +    int64_t size;
>> +
>> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-memory-block-info'}");
>> +    g_assert_nonnull(ret);
>> +    qmp_assert_no_error(ret);
>> +
>> +    /* check there is at least some memory */
>> +    val = qdict_get_qdict(ret, "return");
>> +    size = qdict_get_int(val, "size");
>> +    g_assert_cmpint(size, >, 0);
>> +
>> +    QDECREF(ret);
>> +}
>> +
>> +static void test_qga_get_memory_blocks(gconstpointer fix)
>> +{
>> +    const TestFixture *fixture = fix;
>> +    QDict *ret;
>> +    QList *list;
>> +    const QListEntry *entry;
>> +
>> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-memory-blocks'}");
>> +    g_assert_nonnull(ret);
>> +    qmp_assert_no_error(ret);
>> +
>> +    list = qdict_get_qlist(ret, "return");
>> +    entry = qlist_first(list);
>> +    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "phys-index"));
>> +    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "online"));
>> +
>> +    QDECREF(ret);
>> +}
>> +
>> +static void test_qga_network_get_interfaces(gconstpointer fix)
>> +{
>> +    const TestFixture *fixture = fix;
>> +    QDict *ret;
>> +    QList *list;
>> +    const QListEntry *entry;
>> +
>> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-network-get-interfaces'}");
>> +    g_assert_nonnull(ret);
>> +    qmp_assert_no_error(ret);
>> +
>> +    /* check there is at least a cpu */
>
> copy/paste artifact
>
>> +    list = qdict_get_qlist(ret, "return");
>> +    entry = qlist_first(list);
>> +    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "name"));
>> +
>> +    QDECREF(ret);
>> +}
>> +
>> +static void test_qga_file_ops(gconstpointer fix)
>> +{
>> +    const TestFixture *fixture = fix;
>> +    gchar *cmd, *path;
>> +    const gchar *b64;
>> +    QDict *ret, *val;
>> +    int64_t id, count, eof;
>> +    FILE *f;
>> +    char tmp[100];
>> +
>> +    /* open */
>> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-file-open',"
>> +                 " 'arguments': { 'path': 'foo', 'mode': 'w+' } }");
>> +    g_assert_nonnull(ret);
>> +    qmp_assert_no_error(ret);
>> +    id = qdict_get_int(ret, "return");
>> +    QDECREF(ret);
>> +
>> +    /* write */
>> +    cmd = g_strdup_printf("{'execute': 'guest-file-write',"
>> +                          " 'arguments': { 'handle': %" G_GINT64_FORMAT ","
>> +                          " 'buf-b64': 'aGVsbG8gd29ybGQK' } }", id);
>> +    ret = qmp_fd(fixture->fd, cmd);
>> +    g_assert_nonnull(ret);
>> +    qmp_assert_no_error(ret);
>> +
>> +    val = qdict_get_qdict(ret, "return");
>> +    count = qdict_get_int(val, "count");
>> +    eof = qdict_get_bool(val, "eof");
>> +    g_assert_cmpint(count, ==, 12);
>> +    g_assert_cmpint(eof, ==, 0);
>> +    QDECREF(ret);
>> +    g_free(cmd);
>> +
>> +    /* flush */
>> +    cmd = g_strdup_printf("{'execute': 'guest-file-flush',"
>> +                          " 'arguments': {'handle': %" G_GINT64_FORMAT "} }",
>> +                          id);
>> +    ret = qmp_fd(fixture->fd, cmd);
>> +    QDECREF(ret);
>> +    g_free(cmd);
>> +
>> +    /* close */
>> +    cmd = g_strdup_printf("{'execute': 'guest-file-close',"
>> +                          " 'arguments': {'handle': %" G_GINT64_FORMAT "} }",
>> +                          id);
>> +    ret = qmp_fd(fixture->fd, cmd);
>> +    QDECREF(ret);
>> +    g_free(cmd);
>> +
>> +    /* check content */
>> +    path = g_build_filename(fixture->test_dir, "foo", NULL);
>> +    f = fopen(path, "r");
>> +    g_assert_nonnull(f);
>> +    count = fread(tmp, 1, sizeof(tmp), f);
>> +    g_assert_cmpint(count, ==, 12);
>> +    tmp[count] = 0;
>> +    g_assert_cmpstr(tmp, ==, "hello world\n");
>> +    fclose(f);
>> +
>> +    /* open */
>> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-file-open',"
>> +                 " 'arguments': { 'path': 'foo', 'mode': 'r' } }");
>> +    g_assert_nonnull(ret);
>> +    qmp_assert_no_error(ret);
>> +    id = qdict_get_int(ret, "return");
>> +    QDECREF(ret);
>> +
>> +    /* read */
>> +    cmd = g_strdup_printf("{'execute': 'guest-file-read',"
>> +                          " 'arguments': { 'handle': %" G_GINT64_FORMAT "} }",
>> +                          id);
>> +    ret = qmp_fd(fixture->fd, cmd);
>> +    val = qdict_get_qdict(ret, "return");
>> +    count = qdict_get_int(val, "count");
>> +    eof = qdict_get_bool(val, "eof");
>> +    b64 = qdict_get_str(val, "buf-b64");
>> +    g_assert_cmpint(count, ==, 12);
>> +    g_assert(eof);
>> +    g_assert_cmpstr(b64, ==, "aGVsbG8gd29ybGQK");
>> +
>> +    QDECREF(ret);
>> +    g_free(cmd);
>> +
>> +    /* read eof */
>> +    cmd = g_strdup_printf("{'execute': 'guest-file-read',"
>> +                          " 'arguments': { 'handle': %" G_GINT64_FORMAT "} }",
>> +                          id);
>> +    ret = qmp_fd(fixture->fd, cmd);
>> +    val = qdict_get_qdict(ret, "return");
>> +    count = qdict_get_int(val, "count");
>> +    eof = qdict_get_bool(val, "eof");
>> +    b64 = qdict_get_str(val, "buf-b64");
>> +    g_assert_cmpint(count, ==, 0);
>> +    g_assert(eof);
>> +    g_assert_cmpstr(b64, ==, "");
>> +    QDECREF(ret);
>> +    g_free(cmd);
>> +
>> +    /* seek */
>> +    cmd = g_strdup_printf("{'execute': 'guest-file-seek',"
>> +                          " 'arguments': { 'handle': %" G_GINT64_FORMAT ", "
>> +                          " 'offset': %d, 'whence': %d } }",
>> +                          id, 6, SEEK_SET);
>> +    ret = qmp_fd(fixture->fd, cmd);
>> +    qmp_assert_no_error(ret);
>> +    val = qdict_get_qdict(ret, "return");
>> +    count = qdict_get_int(val, "position");
>> +    eof = qdict_get_bool(val, "eof");
>> +    g_assert_cmpint(count, ==, 6);
>> +    g_assert(!eof);
>> +    QDECREF(ret);
>> +    g_free(cmd);
>> +
>> +    /* partial read */
>> +    cmd = g_strdup_printf("{'execute': 'guest-file-read',"
>> +                          " 'arguments': { 'handle': %" G_GINT64_FORMAT "} }",
>> +                          id);
>> +    ret = qmp_fd(fixture->fd, cmd);
>> +    val = qdict_get_qdict(ret, "return");
>> +    count = qdict_get_int(val, "count");
>> +    eof = qdict_get_bool(val, "eof");
>> +    b64 = qdict_get_str(val, "buf-b64");
>> +    g_assert_cmpint(count, ==, 6);
>> +    g_assert(eof);
>> +    g_assert_cmpstr(b64, ==, "d29ybGQK");
>> +
>> +    QDECREF(ret);
>> +    g_free(cmd);
>> +
>> +    /* close */
>> +    cmd = g_strdup_printf("{'execute': 'guest-file-close',"
>> +                          " 'arguments': {'handle': %" G_GINT64_FORMAT "} }",
>> +                          id);
>> +    ret = qmp_fd(fixture->fd, cmd);
>
> I like having a complex test to make sure all the guest-file-* commands
> interact properly, but would be good if we could preceed this with
> simpler guest-file-* tests that test each command more granularly.
>
> That could be added as a follow-up though, since this is still a good
> test to have.

Ok, I'll leave this for now

>
>> +    QDECREF(ret);
>> +    g_free(cmd);
>> +}
>> +
>> +static void test_qga_get_time(gconstpointer fix)
>> +{
>> +    const TestFixture *fixture = fix;
>> +    QDict *ret;
>> +    int64_t time;
>> +
>> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-time'}");
>> +    g_assert_nonnull(ret);
>> +    qmp_assert_no_error(ret);
>> +
>> +    time = qdict_get_int(ret, "return");
>> +    g_assert_cmpint(time, >, 0);
>> +
>> +    QDECREF(ret);
>> +}
>> +
>> +static void test_qga_set_time(gconstpointer fix)
>> +{
>> +    const TestFixture *fixture = fix;
>> +    QDict *ret;
>> +    int64_t current, time;
>> +    gchar *cmd;
>> +
>> +    /* get current time */
>> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-time'}");
>> +    g_assert_nonnull(ret);
>> +    qmp_assert_no_error(ret);
>> +    current = qdict_get_int(ret, "return");
>> +    g_assert_cmpint(current, >, 0);
>> +    QDECREF(ret);
>> +
>> +    /* set some old time */
>> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-set-time',"
>> +                 " 'arguments': { 'time': 1000 } }");
>> +    g_assert_nonnull(ret);
>> +    qmp_assert_no_error(ret);
>> +    QDECREF(ret);
>> +
>> +    /* check old time */
>> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-time'}");
>> +    g_assert_nonnull(ret);
>> +    qmp_assert_no_error(ret);
>> +    time = qdict_get_int(ret, "return");
>> +    g_assert_cmpint(time / 1000, <, G_USEC_PER_SEC * 10);
>> +    QDECREF(ret);
>> +
>> +    /* set back current time */
>> +    cmd = g_strdup_printf("{'execute': 'guest-set-time',"
>> +                          " 'arguments': { 'time': %" G_GINT64_FORMAT " } }",
>> +                          current + time * 1000);
>> +    ret = qmp_fd(fixture->fd, cmd);
>
> Little concerned about playing with host time in our unit tests. Maybe
> this sort of test should only be enabled if a flag is set, and turned
> of by default?
>
> Ah, I see that's where running_in_virt() comes into play. Nice :)

Yes, but what are the odds to run the qga test on kvm guest with root
privileges? so I think it's fairly safe and still useful.

>
>> +    g_free(cmd);
>> +    g_assert_nonnull(ret);
>> +    qmp_assert_no_error(ret);
>> +    QDECREF(ret);
>> +}
>> +
>> +static void test_qga_fstrim(gconstpointer fix)
>> +{
>> +    const TestFixture *fixture = fix;
>> +    QDict *ret;
>> +    QList *list;
>> +    const QListEntry *entry;
>> +
>> +    /* get current time */
>
> copy/paste artifact

correct, removed

>
>> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-fstrim',"
>> +                 " arguments: { minimum: 4194304 } }");
>> +    g_assert_nonnull(ret);
>> +    qmp_assert_no_error(ret);
>> +    list = qdict_get_qlist(ret, "return");
>> +    entry = qlist_first(list);
>> +    g_assert(qdict_haskey(qobject_to_qdict(entry->value), "paths"));
>> +
>> +    QDECREF(ret);
>> +}
>> +
>> +static void test_qga_blacklist(gconstpointer data)
>> +{
>> +    TestFixture fix;
>> +    QDict *ret, *error;
>> +    const gchar *class, *desc;
>> +
>> +    fixture_setup(&fix, "-b guest-ping,guest-get-time");
>> +
>> +    /* check blacklist */
>> +    ret = qmp_fd(fix.fd, "{'execute': 'guest-ping'}");
>> +    g_assert_nonnull(ret);
>> +    error = qdict_get_qdict(ret, "error");
>> +    class = qdict_get_try_str(error, "class");
>> +    desc = qdict_get_try_str(error, "desc");
>> +    g_assert_cmpstr(class, ==, "GenericError");
>> +    g_assert_nonnull(g_strstr_len(desc, -1, "has been disabled"));
>> +    QDECREF(ret);
>> +
>> +    ret = qmp_fd(fix.fd, "{'execute': 'guest-get-time'}");
>> +    g_assert_nonnull(ret);
>> +    error = qdict_get_qdict(ret, "error");
>> +    class = qdict_get_try_str(error, "class");
>> +    desc = qdict_get_try_str(error, "desc");
>> +    g_assert_cmpstr(class, ==, "GenericError");
>> +    g_assert_nonnull(g_strstr_len(desc, -1, "has been disabled"));
>> +    QDECREF(ret);
>> +
>> +    /* check something work */
>> +    ret = qmp_fd(fix.fd, "{'execute': 'guest-get-fsinfo'}");
>> +    qmp_assert_no_error(ret);
>> +    QDECREF(ret);
>> +
>> +    fixture_tear_down(&fix, NULL);
>> +}
>> +
>> +static void test_qga_fsfreeze_status(gconstpointer fix)
>> +{
>> +    const TestFixture *fixture = fix;
>> +    QDict *ret;
>> +    const gchar *status;
>> +
>> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-fsfreeze-status'}");
>> +    g_assert_nonnull(ret);
>> +    qmp_assert_no_error(ret);
>> +
>> +    status = qdict_get_try_str(ret, "return");
>> +    g_assert_cmpstr(status, ==, "thawed");
>> +
>> +    QDECREF(ret);
>> +}
>> +
>> +static void test_qga_fsfreeze_and_thaw(gconstpointer fix)
>> +{
>> +    const TestFixture *fixture = fix;
>> +    QDict *ret;
>> +    const gchar *status;
>> +
>> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-fsfreeze-freeze'}");
>> +    g_assert_nonnull(ret);
>> +    qmp_assert_no_error(ret);
>> +    QDECREF(ret);
>> +
>> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-fsfreeze-status'}");
>> +    g_assert_nonnull(ret);
>> +    qmp_assert_no_error(ret);
>> +    status = qdict_get_try_str(ret, "return");
>> +    g_assert_cmpstr(status, ==, "frozen");
>> +    QDECREF(ret);
>> +
>> +    ret = qmp_fd(fixture->fd, "{'execute': 'guest-fsfreeze-thaw'}");
>> +    g_assert_nonnull(ret);
>> +    qmp_assert_no_error(ret);
>> +    QDECREF(ret);
>> +}
>> +
>> +static gboolean running_in_virt(const gchar *virt)
>> +{
>> +    gchar *virt_what = NULL;
>> +    gint status;
>> +    gboolean success;
>> +
>> +    success = g_spawn_command_line_sync("virt-what", &virt_what, NULL,
>> +                                        &status, NULL);
>> +
>> +    success = success && status == 0 && g_strcmp0(virt_what, virt);
>> +
>> +    g_free(virt_what);
>> +
>> +    return success;
>> +}
>> +int main(int argc, char **argv)
>> +{
>> +    TestFixture fix;
>> +    int ret;
>> +
>> +    setlocale (LC_ALL, "");
>> +    g_test_init(&argc, &argv, NULL);
>> +    fixture_setup(&fix, NULL);
>> +
>> +    g_test_add_data_func("/qga/sync-delimited", &fix, test_qga_sync_delimited);
>> +    g_test_add_data_func("/qga/sync", &fix, test_qga_sync);
>> +    g_test_add_data_func("/qga/ping", &fix, test_qga_ping);
>> +    g_test_add_data_func("/qga/info", &fix, test_qga_info);
>> +    g_test_add_data_func("/qga/network-get-interfaces", &fix,
>> +                         test_qga_network_get_interfaces);
>> +    g_test_add_data_func("/qga/get-vcpus", &fix, test_qga_get_vcpus);
>> +    g_test_add_data_func("/qga/get-fsinfo", &fix, test_qga_get_fsinfo);
>> +    g_test_add_data_func("/qga/get-memory-block-info", &fix,
>> +                         test_qga_get_memory_block_info);
>> +    g_test_add_data_func("/qga/get-memory-blocks", &fix,
>> +                         test_qga_get_memory_blocks);
>> +    g_test_add_data_func("/qga/file-ops", &fix, test_qga_file_ops);
>> +    g_test_add_data_func("/qga/get-time", &fix, test_qga_get_time);
>> +    g_test_add_data_func("/qga/invalid-cmd", &fix, test_qga_invalid_cmd);
>> +    g_test_add_data_func("/qga/fsfreeze-status", &fix,
>> +                         test_qga_fsfreeze_status);
>> +
>> +    g_test_add_data_func("/qga/blacklist", NULL, test_qga_blacklist);
>> +
>> +    if (running_in_virt("kvm")) {
>> +        g_test_add_data_func("/qga/fsfreeze-and-thaw", &fix,
>> +                             test_qga_fsfreeze_and_thaw);
>> +        g_test_add_data_func("/qga/set-time", &fix, test_qga_set_time);
>> +        if (g_test_thorough()) {
>> +            g_test_add_data_func("/qga/fstrim", &fix, test_qga_fstrim);
>> +        }
>> +    }
>> +
>> +    ret = g_test_run();
>> +
>> +    fixture_tear_down(&fix, NULL);
>> +
>> +    return ret;
>> +}
>> --
>> 2.4.3
>>
>
>

thanks

-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2015-09-11 17:46 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-08-27 10:52 [Qemu-devel] [PATCH 1/2] qtest: add a few fd-level qmp helpers marcandre.lureau
2015-08-27 10:52 ` [Qemu-devel] [PATCH 2/2] tests: add a local test for guest agent marcandre.lureau
2015-08-27 11:36   ` Marc-André Lureau
2015-09-09 17:36     ` Michael Roth
2015-09-09 21:53   ` Michael Roth
2015-09-11 17:46     ` Marc-André Lureau
2015-09-09 20:05 ` [Qemu-devel] [PATCH 1/2] qtest: add a few fd-level qmp helpers Michael Roth

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.