Add a test that simulates a long running process (by using a named pipe
to synchronize). This test ensures that full output is returned with
each call to guest-exec-status.

Signed-off-by: Daniel Xu <d...@dxuuu.xyz>
---
 tests/unit/test-qga.c | 77 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 77 insertions(+)

diff --git a/tests/unit/test-qga.c b/tests/unit/test-qga.c
index 671e83cb86..455183e60b 100644
--- a/tests/unit/test-qga.c
+++ b/tests/unit/test-qga.c
@@ -952,6 +952,81 @@ static void test_qga_guest_exec_merged(gconstpointer fix)
 }
 #endif
 
+#if defined(G_OS_WIN32)
+static void test_qga_guest_exec_stream(gconstpointer fix)
+{
+}
+#else
+static void test_qga_guest_exec_stream(gconstpointer fix)
+{
+    const TestFixture *fixture = fix;
+    g_autoptr(QDict) ret = NULL;
+    g_autofree char *fifo_path = NULL;
+    g_autofree char *cmd = NULL;
+    QDict *val;
+    const gchar *out;
+    g_autofree guchar *decoded = NULL;
+    int64_t pid, exitcode;
+    bool exited;
+    gsize len;
+    int fifo;
+
+    fifo_path = g_strdup_printf("%s/fifo", fixture->test_dir);
+    g_assert_cmpint(mkfifo(fifo_path, 0644), ==, 0);
+
+    /* Echo two lines with a fifo barrier in between */
+    cmd = g_strdup_printf("echo line1; cat %s; echo line2;", fifo_path);
+    ret = qmp_fd(fixture->fd, "{'execute': 'guest-exec', 'arguments': {"
+                 " 'path': '/bin/bash',"
+                 " 'arg': [ '-c', %s ],"
+                 " 'capture-output': 'stdout',"
+                 " 'stream-output': true } }",
+                 cmd);
+    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);
+
+    /* Give bash some time to run */
+    usleep(G_USEC_PER_SEC / 20);
+
+    /* Check first line comes out */
+    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");
+    g_assert_false(exited);
+    out = qdict_get_str(val, "out-data");
+    decoded = g_base64_decode(out, &len);
+    g_assert_cmpint(len, ==, 6);
+    g_assert_cmpstr((char *)decoded, ==, "line1\n");
+    g_free(decoded);
+    qobject_unref(ret);
+
+    /* Trigger second line */
+    fifo = open(fifo_path, O_WRONLY);
+    g_assert_cmpint(fifo, >=, 0);
+    close(fifo);
+    ret = wait_for_guest_exec_completion(fixture->fd, pid);
+
+    /* Check second line comes out after process exits */
+    val = qdict_get_qdict(ret, "return");
+    exited = qdict_get_bool(val, "exited");
+    g_assert_true(exited);
+    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, ==, "line1\nline2\n");
+    g_assert_cmpint(unlink(fifo_path), ==, 0);
+}
+#endif
+
 static void test_qga_guest_exec_invalid(gconstpointer fix)
 {
     const TestFixture *fixture = fix;
@@ -1127,6 +1202,8 @@ int main(int argc, char **argv)
                          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-stream", &fix,
+                         test_qga_guest_exec_stream);
     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,
-- 
2.41.0


Reply via email to