g_usleep(G_USEC_PER_SEC);
}
if (i++ == 10) {
+ close(s);
return -1;
}
} while (ret == -1);
{
const gchar *extra_arg = data;
GError *error = NULL;
- gchar *cwd, *path, *cmd, **argv = NULL;
+ g_autofree char *cwd = NULL;
+ g_autofree char *path = NULL;
+ g_autofree char *cmd = NULL;
+ g_auto(GStrv) argv = NULL;
fixture->loop = g_main_loop_new(NULL, FALSE);
- fixture->test_dir = g_strdup("/tmp/qgatest.XXXXXX");
- g_assert_nonnull(mkdtemp(fixture->test_dir));
+ fixture->test_dir = g_strdup_printf("%s/qgatest.XXXXXX", g_get_tmp_dir());
+ g_assert_nonnull(g_mkdtemp(fixture->test_dir));
path = g_build_filename(fixture->test_dir, "sock", NULL);
cwd = g_get_current_dir();
fixture->fd = connect_qga(path);
g_assert_cmpint(fixture->fd, !=, -1);
-
- g_strfreev(argv);
- g_free(cmd);
- g_free(cwd);
- g_free(path);
}
static void
fixture_tear_down(TestFixture *fixture, gconstpointer data)
{
- gchar *tmp;
+ g_autofree char *tmp = NULL;
kill(fixture->pid, SIGTERM);
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);
QDict *dict)
{
const char *class, *desc;
- char *s;
+ g_autofree char *s = NULL;
QDict *error;
error = qdict_get_qdict(dict, "error");
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 { \
const TestFixture *fixture = fix;
guint32 v, r = g_test_rand_int();
unsigned char c;
- QDict *ret;
+ g_autoptr(QDict) ret = NULL;
qmp_fd_send_raw(fixture->fd, "\xff");
qmp_fd_send(fixture->fd,
v = qdict_get_int(ret, "return");
g_assert_cmpint(r, ==, v);
-
- qobject_unref(ret);
}
static void test_qga_sync(gconstpointer fix)
{
const TestFixture *fixture = fix;
guint32 v, r = g_test_rand_int();
- QDict *ret;
+ g_autoptr(QDict) ret = NULL;
/*
* TODO guest-sync is inherently limited: we cannot distinguish
v = qdict_get_int(ret, "return");
g_assert_cmpint(r, ==, v);
-
- qobject_unref(ret);
}
static void test_qga_ping(gconstpointer fix)
{
const TestFixture *fixture = fix;
- QDict *ret;
+ g_autoptr(QDict) ret = NULL;
ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping'}");
g_assert_nonnull(ret);
qmp_assert_no_error(ret);
-
- qobject_unref(ret);
}
static void test_qga_id(gconstpointer fix)
{
const TestFixture *fixture = fix;
- QDict *ret;
+ g_autoptr(QDict) ret = NULL;
ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping', 'id': 1}");
g_assert_nonnull(ret);
qmp_assert_no_error(ret);
g_assert_cmpint(qdict_get_int(ret, "id"), ==, 1);
-
- qobject_unref(ret);
}
static void test_qga_invalid_oob(gconstpointer fix)
static void test_qga_invalid_args(gconstpointer fix)
{
const TestFixture *fixture = fix;
- QDict *ret, *error;
+ g_autoptr(QDict) ret = NULL;
+ QDict *error;
const gchar *class, *desc;
ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping', "
g_assert_cmpstr(class, ==, "GenericError");
g_assert_cmpstr(desc, ==, "Parameter 'foo' is unexpected");
-
- qobject_unref(ret);
}
static void test_qga_invalid_cmd(gconstpointer fix)
{
const TestFixture *fixture = fix;
- QDict *ret, *error;
+ g_autoptr(QDict) ret = NULL;
+ QDict *error;
const gchar *class, *desc;
ret = qmp_fd(fixture->fd, "{'execute': 'guest-invalid-cmd'}");
g_assert_cmpstr(class, ==, "CommandNotFound");
g_assert_cmpint(strlen(desc), >, 0);
-
- qobject_unref(ret);
}
static void test_qga_info(gconstpointer fix)
{
const TestFixture *fixture = fix;
- QDict *ret, *val;
+ g_autoptr(QDict) ret = NULL;
+ QDict *val;
const gchar *version;
ret = qmp_fd(fixture->fd, "{'execute': 'guest-info'}");
val = qdict_get_qdict(ret, "return");
version = qdict_get_try_str(val, "version");
g_assert_cmpstr(version, ==, QEMU_VERSION);
-
- qobject_unref(ret);
}
static void test_qga_get_vcpus(gconstpointer fix)
{
const TestFixture *fixture = fix;
- QDict *ret;
+ g_autoptr(QDict) ret = NULL;
QList *list;
const QListEntry *entry;
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"));
-
- qobject_unref(ret);
}
static void test_qga_get_fsinfo(gconstpointer fix)
{
const TestFixture *fixture = fix;
- QDict *ret;
+ g_autoptr(QDict) ret = NULL;
QList *list;
const QListEntry *entry;
g_assert(qdict_haskey(qobject_to(QDict, entry->value), "type"));
g_assert(qdict_haskey(qobject_to(QDict, entry->value), "disk"));
}
-
- qobject_unref(ret);
}
static void test_qga_get_memory_block_info(gconstpointer fix)
{
const TestFixture *fixture = fix;
- QDict *ret, *val;
+ g_autoptr(QDict) ret = NULL;
+ QDict *val;
int64_t size;
ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-memory-block-info'}");
size = qdict_get_int(val, "size");
g_assert_cmpint(size, >, 0);
}
-
- qobject_unref(ret);
}
static void test_qga_get_memory_blocks(gconstpointer fix)
{
const TestFixture *fixture = fix;
- QDict *ret;
+ g_autoptr(QDict) ret = NULL;
QList *list;
const QListEntry *entry;
g_assert(qdict_haskey(qobject_to(QDict, entry->value), "online"));
}
}
-
- qobject_unref(ret);
}
static void test_qga_network_get_interfaces(gconstpointer fix)
{
const TestFixture *fixture = fix;
- QDict *ret;
+ g_autoptr(QDict) ret = NULL;
QList *list;
const QListEntry *entry;
list = qdict_get_qlist(ret, "return");
entry = qlist_first(list);
g_assert(qdict_haskey(qobject_to(QDict, entry->value), "name"));
-
- qobject_unref(ret);
}
static void test_qga_file_ops(gconstpointer fix)
static void test_qga_get_time(gconstpointer fix)
{
const TestFixture *fixture = fix;
- QDict *ret;
+ g_autoptr(QDict) ret = NULL;
int64_t time;
ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-time'}");
time = qdict_get_int(ret, "return");
g_assert_cmpint(time, >, 0);
-
- qobject_unref(ret);
}
-static void test_qga_blacklist(gconstpointer data)
+static void test_qga_blockedrpcs(gconstpointer data)
{
TestFixture fix;
QDict *ret, *error;
fixture_setup(&fix, "-b guest-ping,guest-get-time", NULL);
- /* check blacklist */
+ /* check blocked RPCs */
ret = qmp_fd(fix.fd, "{'execute': 'guest-ping'}");
g_assert_nonnull(ret);
error = qdict_get_qdict(ret, "error");
fixture_tear_down(&fix, NULL);
}
+static void test_qga_allowedrpcs(gconstpointer data)
+{
+ TestFixture fix;
+ QDict *ret, *error;
+ const gchar *class, *desc;
+
+ fixture_setup(&fix, "-a guest-ping,guest-get-time", NULL);
+
+ /* check allowed RPCs */
+ ret = qmp_fd(fix.fd, "{'execute': 'guest-ping'}");
+ qmp_assert_no_error(ret);
+ qobject_unref(ret);
+
+ ret = qmp_fd(fix.fd, "{'execute': 'guest-get-time'}");
+ qmp_assert_no_error(ret);
+ qobject_unref(ret);
+
+ /* check something else */
+ ret = qmp_fd(fix.fd, "{'execute': 'guest-get-fsinfo'}");
+ 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_nonnull(g_strstr_len(desc, -1, "has been disabled"));
+ qobject_unref(ret);
+
+ fixture_tear_down(&fix, NULL);
+}
+
static void test_qga_config(gconstpointer data)
{
GError *error = NULL;
- char *cwd, *cmd, *out, *err, *str, **strv, **argv = NULL;
+ g_autofree char *out = NULL;
+ g_autofree char *err = NULL;
+ g_autofree char *cwd = NULL;
+ g_autofree char *cmd = NULL;
+ g_auto(GStrv) argv = NULL;
+ g_auto(GStrv) strv = NULL;
+ g_autoptr(GKeyFile) kf = NULL;
+ char *str;
char *env[2];
int status;
gsize n;
- GKeyFile *kf;
cwd = g_get_current_dir();
cmd = g_strdup_printf("%s%cqga%cqemu-ga -D",
cwd, G_DIR_SEPARATOR, G_DIR_SEPARATOR);
- g_free(cwd);
g_shell_parse_argv(cmd, NULL, &argv, &error);
- g_free(cmd);
g_assert_no_error(error);
env[0] = g_strdup_printf("QGA_CONF=tests%cdata%ctest-qga-config",
env[1] = NULL;
g_spawn_sync(NULL, argv, env, 0,
NULL, NULL, &out, &err, &status, &error);
- g_strfreev(argv);
g_assert_no_error(error);
g_assert_cmpstr(err, ==, "");
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);
+ strv = g_key_file_get_string_list(kf, "general", "block-rpcs", &n, &error);
g_assert_cmpint(n, ==, 2);
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"));
g_assert_no_error(error);
- g_strfreev(strv);
- g_free(out);
- g_free(err);
g_free(env[0]);
- g_key_file_free(kf);
}
static void test_qga_fsfreeze_status(gconstpointer fix)
{
const TestFixture *fixture = fix;
- QDict *ret;
+ g_autoptr(QDict) ret = NULL;
const gchar *status;
ret = qmp_fd(fixture->fd, "{'execute': 'guest-fsfreeze-status'}");
status = qdict_get_try_str(ret, "return");
g_assert_cmpstr(status, ==, "thawed");
+}
- qobject_unref(ret);
+static QDict *wait_for_guest_exec_completion(int fd, int64_t pid)
+{
+ QDict *ret = NULL;
+ int64_t now;
+ bool exited;
+ QDict *val;
+
+ now = g_get_monotonic_time();
+ do {
+ ret = qmp_fd(fd,
+ "{'execute': 'guest-exec-status',"
+ " 'arguments': { 'pid': %" PRId64 " } }", pid);
+ g_assert_nonnull(ret);
+ val = qdict_get_qdict(ret, "return");
+ exited = qdict_get_bool(val, "exited");
+ if (!exited) {
+ qobject_unref(ret);
+ }
+ } while (!exited &&
+ g_get_monotonic_time() < now + 5 * G_TIME_SPAN_SECOND);
+ g_assert(exited);
+
+ return ret;
}
static void test_qga_guest_exec(gconstpointer fix)
{
const TestFixture *fixture = fix;
- QDict *ret, *val;
+ g_autoptr(QDict) ret = NULL;
+ QDict *val;
const gchar *out;
- guchar *decoded;
- int64_t pid, now, exitcode;
+ g_autofree guchar *decoded = NULL;
+ int64_t pid, exitcode;
gsize len;
- bool exited;
/* exec 'echo foo bar' */
ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec', 'arguments': {"
- " 'path': '/bin/echo', 'arg': [ '-n', '\" test_str \"' ],"
+ " 'path': 'echo', 'arg': [ '-n', '\" test_str \"' ],"
" 'capture-output': true } }");
g_assert_nonnull(ret);
qmp_assert_no_error(ret);
g_assert_cmpint(pid, >, 0);
qobject_unref(ret);
- /* wait for completion */
- now = g_get_monotonic_time();
- do {
- ret = qmp_fd(fixture->fd,
- "{'execute': 'guest-exec-status',"
- " 'arguments': { 'pid': %" PRId64 " } }", pid);
- g_assert_nonnull(ret);
- val = qdict_get_qdict(ret, "return");
- exited = qdict_get_bool(val, "exited");
- if (!exited) {
- qobject_unref(ret);
- }
- } while (!exited &&
- g_get_monotonic_time() < now + 5 * G_TIME_SPAN_SECOND);
- g_assert(exited);
+ ret = wait_for_guest_exec_completion(fixture->fd, pid);
/* check stdout */
+ val = qdict_get_qdict(ret, "return");
exitcode = qdict_get_int(val, "exitcode");
g_assert_cmpint(exitcode, ==, 0);
out = qdict_get_str(val, "out-data");
decoded = g_base64_decode(out, &len);
g_assert_cmpint(len, ==, 12);
g_assert_cmpstr((char *)decoded, ==, "\" test_str \"");
- g_free(decoded);
+}
+
+#if defined(G_OS_WIN32)
+static void test_qga_guest_exec_separated(gconstpointer fix)
+{
+}
+static void test_qga_guest_exec_merged(gconstpointer fix)
+{
+ const TestFixture *fixture = fix;
+ g_autoptr(QDict) ret = NULL;
+ QDict *val;
+ const gchar *class, *desc;
+ g_autofree guchar *decoded = NULL;
+
+ /* exec 'echo foo bar' */
+ ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec', 'arguments': {"
+ " 'path': 'echo',"
+ " 'arg': [ 'execution never reaches here' ],"
+ " 'capture-output': 'merged' } }");
+
+ g_assert_nonnull(ret);
+ val = qdict_get_qdict(ret, "error");
+ g_assert_nonnull(val);
+ class = qdict_get_str(val, "class");
+ desc = qdict_get_str(val, "desc");
+ g_assert_cmpstr(class, ==, "GenericError");
+ g_assert_cmpint(strlen(desc), >, 0);
+}
+#else
+static void test_qga_guest_exec_separated(gconstpointer fix)
+{
+ const TestFixture *fixture = fix;
+ g_autoptr(QDict) ret = NULL;
+ QDict *val;
+ const gchar *out, *err;
+ g_autofree guchar *out_decoded = NULL;
+ g_autofree guchar *err_decoded = NULL;
+ int64_t pid, exitcode;
+ gsize len;
+
+ /* exec 'echo foo bar' */
+ ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec', 'arguments': {"
+ " 'path': 'bash',"
+ " 'arg': [ '-c', 'for i in $(seq 4); do if (( $i %% 2 )); then echo stdout; else echo stderr 1>&2; fi; done;' ],"
+ " 'capture-output': 'separated' } }");
+ g_assert_nonnull(ret);
+ qmp_assert_no_error(ret);
+ val = qdict_get_qdict(ret, "return");
+ pid = qdict_get_int(val, "pid");
+ g_assert_cmpint(pid, >, 0);
qobject_unref(ret);
+
+ ret = wait_for_guest_exec_completion(fixture->fd, pid);
+
+ val = qdict_get_qdict(ret, "return");
+ exitcode = qdict_get_int(val, "exitcode");
+ g_assert_cmpint(exitcode, ==, 0);
+
+ /* check stdout */
+ out = qdict_get_str(val, "out-data");
+ out_decoded = g_base64_decode(out, &len);
+ g_assert_cmpint(len, ==, 14);
+ g_assert_cmpstr((char *)out_decoded, ==, "stdout\nstdout\n");
+
+ /* check stderr */
+ err = qdict_get_try_str(val, "err-data");
+ err_decoded = g_base64_decode(err, &len);
+ g_assert_cmpint(len, ==, 14);
+ g_assert_cmpstr((char *)err_decoded, ==, "stderr\nstderr\n");
}
+static void test_qga_guest_exec_merged(gconstpointer fix)
+{
+ const TestFixture *fixture = fix;
+ g_autoptr(QDict) ret = NULL;
+ QDict *val;
+ const gchar *out, *err;
+ g_autofree guchar *decoded = NULL;
+ int64_t pid, exitcode;
+ gsize len;
+
+ /* exec 'echo foo bar' */
+ ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec', 'arguments': {"
+ " 'path': 'bash',"
+ " 'arg': [ '-c', 'for i in $(seq 4); do if (( $i %% 2 )); then echo stdout; else echo stderr 1>&2; fi; done;' ],"
+ " 'capture-output': 'merged' } }");
+ g_assert_nonnull(ret);
+ qmp_assert_no_error(ret);
+ val = qdict_get_qdict(ret, "return");
+ pid = qdict_get_int(val, "pid");
+ g_assert_cmpint(pid, >, 0);
+ qobject_unref(ret);
+
+ ret = wait_for_guest_exec_completion(fixture->fd, pid);
+
+ val = qdict_get_qdict(ret, "return");
+ exitcode = qdict_get_int(val, "exitcode");
+ g_assert_cmpint(exitcode, ==, 0);
+
+ /* check stdout */
+ out = qdict_get_str(val, "out-data");
+ decoded = g_base64_decode(out, &len);
+ g_assert_cmpint(len, ==, 28);
+ g_assert_cmpstr((char *)decoded, ==, "stdout\nstderr\nstdout\nstderr\n");
+
+ /* check stderr */
+ err = qdict_get_try_str(val, "err-data");
+ g_assert_null(err);
+}
+#endif
+
static void test_qga_guest_exec_invalid(gconstpointer fix)
{
const TestFixture *fixture = fix;
- QDict *ret, *error;
+ g_autoptr(QDict) ret = NULL;
+ QDict *error;
const gchar *class, *desc;
/* invalid command */
desc = qdict_get_str(error, "desc");
g_assert_cmpstr(class, ==, "GenericError");
g_assert_cmpint(strlen(desc), >, 0);
- qobject_unref(ret);
}
static void test_qga_guest_get_host_name(gconstpointer fix)
{
const TestFixture *fixture = fix;
- QDict *ret, *val;
+ g_autoptr(QDict) ret = NULL;
+ QDict *val;
ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-host-name'}");
g_assert_nonnull(ret);
val = qdict_get_qdict(ret, "return");
g_assert(qdict_haskey(val, "host-name"));
-
- qobject_unref(ret);
}
static void test_qga_guest_get_timezone(gconstpointer fix)
{
const TestFixture *fixture = fix;
- QDict *ret, *val;
+ g_autoptr(QDict) ret = NULL;
+ QDict *val;
ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-timezone'}");
g_assert_nonnull(ret);
/* Make sure there's at least offset */
val = qdict_get_qdict(ret, "return");
g_assert(qdict_haskey(val, "offset"));
-
- qobject_unref(ret);
}
static void test_qga_guest_get_users(gconstpointer fix)
{
const TestFixture *fixture = fix;
- QDict *ret;
+ g_autoptr(QDict) ret = NULL;
QList *val;
ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-users'}");
/* There is not much to test here */
val = qdict_get_qlist(ret, "return");
g_assert_nonnull(val);
-
- qobject_unref(ret);
}
static void test_qga_guest_get_osinfo(gconstpointer data)
{
TestFixture fixture;
const gchar *str;
- gchar *cwd, *env[2];
- QDict *ret, *val;
+ g_autoptr(QDict) ret = NULL;
+ char *env[2];
+ QDict *val;
- cwd = g_get_current_dir();
env[0] = g_strdup_printf(
- "QGA_OS_RELEASE=%s%ctests%cdata%ctest-qga-os-release",
- cwd, G_DIR_SEPARATOR, G_DIR_SEPARATOR, G_DIR_SEPARATOR);
+ "QGA_OS_RELEASE=%s%c..%cdata%ctest-qga-os-release",
+ g_test_get_dir(G_TEST_DIST), G_DIR_SEPARATOR, G_DIR_SEPARATOR, G_DIR_SEPARATOR);
env[1] = NULL;
- g_free(cwd);
fixture_setup(&fixture, NULL, env);
ret = qmp_fd(fixture.fd, "{'execute': 'guest-get-osinfo'}");
g_assert_nonnull(str);
g_assert_cmpstr(str, ==, "unit-test");
- qobject_unref(ret);
g_free(env[0]);
fixture_tear_down(&fixture, NULL);
}
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/blockedrpcs", NULL, test_qga_blockedrpcs);
+ g_test_add_data_func("/qga/allowedrpcs", NULL, test_qga_allowedrpcs);
g_test_add_data_func("/qga/config", NULL, test_qga_config);
g_test_add_data_func("/qga/guest-exec", &fix, test_qga_guest_exec);
+ g_test_add_data_func("/qga/guest-exec-separated", &fix,
+ test_qga_guest_exec_separated);
+ g_test_add_data_func("/qga/guest-exec-merged", &fix,
+ test_qga_guest_exec_merged);
g_test_add_data_func("/qga/guest-exec-invalid", &fix,
test_qga_guest_exec_invalid);
g_test_add_data_func("/qga/guest-get-osinfo", &fix,