From: Michael Roth <mdroth@linux.vnet.ibm.com>
To: "Marc-André Lureau" <mlureau@redhat.com>
Cc: marcandre lureau <marcandre.lureau@redhat.com>, qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [PATCH v2 4/4] tests: add a local test for guest agent
Date: Thu, 01 Oct 2015 18:36:02 -0500 [thread overview]
Message-ID: <20151001233602.32707.38763@loki> (raw)
In-Reply-To: <841415431.21695592.1443738293222.JavaMail.zimbra@redhat.com>
Quoting Marc-André Lureau (2015-10-01 17:24:53)
>
>
> ----- Original Message -----
> > Quoting marcandre.lureau@redhat.com (2015-09-11 13:53:41)
> > > From: Marc-André Lureau <marcandre.lureau@redhat.com>
> > >
> > > Add some local guest agent tests (as it is better than nothing) only
> > > when CONFIG_LINUX.
> > >
> > > 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>
> >
> > Sorry for the delay in getting to this. Have some review comments but
> > will make sure to stay on top of any follow-ups as I'm trying to get
> > this into my next pull.
> >
> > > ---
> > > tests/Makefile | 3 +
> > > tests/test-qga.c | 791
> > > +++++++++++++++++++++++++++++++++++++++++++++++++++++++
> > > 2 files changed, 794 insertions(+)
> > > create mode 100644 tests/test-qga.c
> > >
> > > diff --git a/tests/Makefile b/tests/Makefile
> > > index 34c6136..d5837a4 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-$(CONFIG_LINUX) += tests/test-qga$(EXESUF)
> > >
> > > check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
> > >
> > > @@ -432,6 +433,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..cfee134
> > > --- /dev/null
> > > +++ b/tests/test-qga.c
> > > @@ -0,0 +1,791 @@
> > > +#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, i = 0;
> > > + 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);
> > > + }
> > > + if (i++ == 5) {
> > > + return -1;
> > > + }
> > > + } 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 */
> >
> > copy/paste error
> >
> > > + 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);
> >
> > base64 encoding the string here would be more readible, or at least just
> > a comment that it's a b64 "hello world". A separate variable/constant to
> > store it so it's not manually duplicated below would be good too in case
> > we ever wanted to change it to check some fringe case with encodings.
> >
> > > + 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");
> >
> > This makes me think doing the b64 encode/decodes here would be a lot
> > easier, especially given that offsets are relative to the plaintext.
> >
> > > +
> > > + 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;
> > > +
> > > + 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);
> > > +}
> > > +
> > > +#if !GLIB_CHECK_VERSION(2, 38, 0)
> > > +#define g_assert_true(E) g_assert(E)
> > > +#define g_assert_false(E) g_assert(!E)
> > > +#endif
> > > +
> > > +static void test_qga_config(gconstpointer data)
> > > +{
> > > + GError *error = NULL;
> > > + char *cwd, *cmd, *out, *err, *str, **strv, *conf, **argv = NULL;
> > > + char *env[2];
> > > + int status, tmp;
> > > + gsize n;
> > > + GKeyFile *kf;
> > > + const char *qga_config =
> > > + "[general]\n"
> > > + "daemon=false\n"
> > > + "method=virtio-serial\n"
> > > + "path=/path/to/org.qemu.guest_agent.0\n"
> > > + "pidfile=/var/foo/qemu-ga.pid\n"
> > > + "statedir=/var/state\n"
> > > + "verbose=true\n"
> > > + "blacklist=guest-ping;guest-get-time\n";
> > > +
> > > + tmp = g_file_open_tmp(NULL, &conf, &error);
> > > + g_assert_no_error(error);
> > > + g_assert_cmpint(tmp, >=, 0);
> > > + g_assert_cmpstr(conf, !=, "");
> > > +
> > > + g_file_set_contents(conf, qga_config, -1, &error);
> > > + g_assert_no_error(error);
> > > +
> > > + cwd = g_get_current_dir();
> > > + cmd = g_strdup_printf("%s%cqemu-ga -D",
> > > + cwd, G_DIR_SEPARATOR);
> > > + g_shell_parse_argv(cmd, NULL, &argv, &error);
> > > + g_assert_no_error(error);
> > > +
> > > + env[0] = g_strdup_printf("QGA_CONF=%s", conf);
> > > + env[1] = NULL;
> > > + g_spawn_sync(NULL, argv, env, G_SPAWN_DEFAULT,
> > > + NULL, NULL, &out, &err, &status, &error);
> > > + g_assert_no_error(error);
> > > + g_assert_cmpstr(err, ==, "");
> > > + g_assert_cmpint(status, ==, 0);
> > > +
> > > + kf = g_key_file_new();
> > > + g_key_file_load_from_data(kf, out, -1, G_KEY_FILE_NONE, &error);
> > > + g_assert_no_error(error);
> > > +
> > > + str = g_key_file_get_start_group(kf);
> > > + g_assert_cmpstr(str, ==, "general");
> > > + g_free(str);
> > > +
> > > + g_assert_false(g_key_file_get_boolean(kf, "general", "daemon",
> > > &error));
> > > + g_assert_no_error(error);
> > > +
> > > + str = g_key_file_get_string(kf, "general", "method", &error);
> > > + g_assert_no_error(error);
> > > + g_assert_cmpstr(str, ==, "virtio-serial");
> > > + g_free(str);
> > > +
> > > + str = g_key_file_get_string(kf, "general", "path", &error);
> > > + g_assert_no_error(error);
> > > + g_assert_cmpstr(str, ==, "/path/to/org.qemu.guest_agent.0");
> > > + g_free(str);
> > > +
> > > + str = g_key_file_get_string(kf, "general", "pidfile", &error);
> > > + g_assert_no_error(error);
> > > + g_assert_cmpstr(str, ==, "/var/foo/qemu-ga.pid");
> > > + g_free(str);
> > > +
> > > + str = g_key_file_get_string(kf, "general", "statedir", &error);
> > > + g_assert_no_error(error);
> > > + g_assert_cmpstr(str, ==, "/var/state");
> > > + g_free(str);
> > > +
> > > + g_assert_true(g_key_file_get_boolean(kf, "general", "verbose",
> > > &error));
> > > + g_assert_no_error(error);
> > > +
> > > + strv = g_key_file_get_string_list(kf, "general", "blacklist", &n,
> > > &error);
> > > + g_assert_cmpint(n, ==, 2);
> > > +#if GLIB_CHECK_VERSION(2, 44, 0)
> > > + g_assert_true(g_strv_contains((const char * const *)strv,
> > > + "guest-ping"));
> > > + g_assert_true(g_strv_contains((const char * const *)strv,
> > > + "guest-get-time"));
> > > +#endif
> > > + g_assert_no_error(error);
> > > + g_strfreev(strv);
> > > +
> > > + g_free(out);
> > > + g_free(err);
> > > + g_free(conf);
> > > + g_free(env[0]);
> > > + g_key_file_free(kf);
> > > +
> > > + close(tmp);
> > > +}
> > > +
> > > +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;
> > > + gchar *err = NULL;
> > > + gint status;
> > > + gboolean success;
> > > +
> > > + success = g_spawn_command_line_sync("virt-what", &virt_what, &err,
> > > + &status, NULL);
> > > +
> > > + success = success && status == 0 &&
> > > + g_strcmp0(g_strstrip(virt_what), virt) == 0;
> > > +
> > > + g_free(virt_what);
> > > + g_free(err);
> > > +
> > > + 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);
> > > + g_test_add_data_func("/qga/config", NULL, test_qga_config);
> > > +
> > > + if (running_in_virt("kvm")) {
> >
> > I think we should go ahead and replace this with a QGA_TEST_SIDE_EFFECTING
> > environment variable or something of the sort. It's not necessarily the
> > case that a VM environment means we can do side-effecting tests. It
> > could be an "official" build server or someone's primary development
>
> But they wouldn't have root privileges though presumably.
>
> > environment and fsfreeze can do some funky stuff if they aren't
> > intentionally running it.
>
> Sounds good to me. Would you pick this patch and make the required modification or do you want a resend?
Actually, I just noticed g_assert_nonnull() was only added in 2.40,
whereas our min is 2.22, so we'll need a wrapper for those. Can you
go ahead and send a respin? We can probably leave the
g_base64_decode/encode suggestion as a potential follow-up.
>
> >
> > > + 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
>
next prev parent reply other threads:[~2015-10-01 23:36 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-09-11 18:53 [Qemu-devel] [PATCH v2 0/4] qga: add local tests on linux marcandre.lureau
2015-09-11 18:53 ` [Qemu-devel] [PATCH v2 1/4] qga: add QGA_CONF environment variable marcandre.lureau
2015-10-01 20:27 ` Michael Roth
2015-09-11 18:53 ` [Qemu-devel] [PATCH v2 2/4] qga: do not override configuration verbosity marcandre.lureau
2015-10-01 20:38 ` Michael Roth
2015-09-11 18:53 ` [Qemu-devel] [PATCH v2 3/4] qtest: add a few fd-level qmp helpers marcandre.lureau
2015-09-11 18:53 ` [Qemu-devel] [PATCH v2 4/4] tests: add a local test for guest agent marcandre.lureau
2015-10-01 21:36 ` Michael Roth
2015-10-01 22:24 ` Marc-André Lureau
2015-10-01 23:36 ` Michael Roth [this message]
2015-09-25 10:15 ` [Qemu-devel] [PATCH v2 0/4] qga: add local tests on linux Marc-André Lureau
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20151001233602.32707.38763@loki \
--to=mdroth@linux.vnet.ibm.com \
--cc=marcandre.lureau@redhat.com \
--cc=mlureau@redhat.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.