[PATCH 4/5] tests/qtest: add tests for dynamic monitor add/remove

Christian Brauner posted 5 patches 1 week, 1 day ago
Maintainers: "Dr. David Alan Gilbert" <dave@treblig.org>, Markus Armbruster <armbru@redhat.com>, Eric Blake <eblake@redhat.com>, Thomas Huth <th.huth+qemu@posteo.eu>, "Philippe Mathieu-Daudé" <philmd@linaro.org>, "Daniel P. Berrangé" <berrange@redhat.com>, Fabiano Rosas <farosas@suse.de>, Laurent Vivier <lvivier@redhat.com>, Paolo Bonzini <pbonzini@redhat.com>
There is a newer version of this series
[PATCH 4/5] tests/qtest: add tests for dynamic monitor add/remove
Posted by Christian Brauner 1 week, 1 day ago
Test the monitor-add, monitor-remove, and query-monitors QMP commands:

- Basic lifecycle: chardev-add -> monitor-add -> query-monitors ->
  monitor-remove -> chardev-remove
- Error: duplicate monitor id
- Error: monitor-remove on nonexistent id
- Error: monitor-add with nonexistent chardev
- Re-add after remove: same id and chardev reusable after removal

Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 tests/qtest/qmp-test.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 101 insertions(+)

diff --git a/tests/qtest/qmp-test.c b/tests/qtest/qmp-test.c
index edf0886787..9dbd3a6103 100644
--- a/tests/qtest/qmp-test.c
+++ b/tests/qtest/qmp-test.c
@@ -337,6 +337,105 @@ static void test_qmp_missing_any_arg(void)
     qtest_quit(qts);
 }
 
+static void test_qmp_monitor_add_remove(void)
+{
+    QTestState *qts;
+    QDict *resp;
+
+    qts = qtest_init(common_args);
+
+    /* Create a null chardev for the dynamic monitor */
+    resp = qtest_qmp(qts,
+                     "{'execute': 'chardev-add',"
+                     " 'arguments': {'id': 'monitor-chardev',"
+                     "               'backend': {'type': 'null',"
+                     "                           'data': {}}}}");
+    g_assert(qdict_haskey(resp, "return"));
+    qobject_unref(resp);
+
+    /* Add a dynamic monitor */
+    resp = qtest_qmp(qts,
+                     "{'execute': 'monitor-add',"
+                     " 'arguments': {'id': 'dyn-mon',"
+                     "               'chardev': 'monitor-chardev'}}");
+    g_assert(qdict_haskey(resp, "return"));
+    qobject_unref(resp);
+
+    /* Verify it shows up in query-monitors */
+    resp = qtest_qmp(qts, "{'execute': 'query-monitors'}");
+    g_assert(!qdict_haskey(resp, "error"));
+    qobject_unref(resp);
+
+    /* Error: duplicate id */
+    resp = qtest_qmp(qts,
+                     "{'execute': 'monitor-add',"
+                     " 'arguments': {'id': 'dyn-mon',"
+                     "               'chardev': 'monitor-chardev'}}");
+    qmp_expect_error_and_unref(resp, "GenericError");
+
+    /* Remove the dynamic monitor */
+    resp = qtest_qmp(qts,
+                     "{'execute': 'monitor-remove',"
+                     " 'arguments': {'id': 'dyn-mon'}}");
+    g_assert(qdict_haskey(resp, "return"));
+    qobject_unref(resp);
+
+    /* Error: remove nonexistent */
+    resp = qtest_qmp(qts,
+                     "{'execute': 'monitor-remove',"
+                     " 'arguments': {'id': 'dyn-mon'}}");
+    qmp_expect_error_and_unref(resp, "GenericError");
+
+    /* Error: remove CLI monitor (the default one) -- find its id first.
+     * CLI monitors typically have no id, so use a bogus id to test. */
+
+    /* Add again after remove -- same id and chardev should work */
+    resp = qtest_qmp(qts,
+                     "{'execute': 'monitor-add',"
+                     " 'arguments': {'id': 'dyn-mon',"
+                     "               'chardev': 'monitor-chardev'}}");
+    g_assert(qdict_haskey(resp, "return"));
+    qobject_unref(resp);
+
+    /* Clean up */
+    resp = qtest_qmp(qts,
+                     "{'execute': 'monitor-remove',"
+                     " 'arguments': {'id': 'dyn-mon'}}");
+    g_assert(qdict_haskey(resp, "return"));
+    qobject_unref(resp);
+
+    resp = qtest_qmp(qts,
+                     "{'execute': 'chardev-remove',"
+                     " 'arguments': {'id': 'monitor-chardev'}}");
+    g_assert(qdict_haskey(resp, "return"));
+    qobject_unref(resp);
+
+    qtest_quit(qts);
+}
+
+static void test_qmp_monitor_error_paths(void)
+{
+    QTestState *qts;
+    QDict *resp;
+
+    qts = qtest_init(common_args);
+
+    /* Error: chardev does not exist */
+    resp = qtest_qmp(qts,
+                     "{'execute': 'monitor-add',"
+                     " 'arguments': {'id': 'bad-mon',"
+                     "               'chardev': 'nonexistent'}}");
+    qmp_expect_error_and_unref(resp, "GenericError");
+
+    /* Error: remove nonexistent monitor */
+    resp = qtest_qmp(qts,
+                     "{'execute': 'monitor-remove',"
+                     " 'arguments': {'id': 'bogus'}}");
+    qmp_expect_error_and_unref(resp, "GenericError");
+
+    qtest_quit(qts);
+}
+
 int main(int argc, char *argv[])
 {
     g_test_init(&argc, &argv, NULL);
@@ -348,6 +447,8 @@ int main(int argc, char *argv[])
 #endif
     qtest_add_func("qmp/preconfig", test_qmp_preconfig);
     qtest_add_func("qmp/missing-any-arg", test_qmp_missing_any_arg);
+    qtest_add_func("qmp/monitor-add-remove", test_qmp_monitor_add_remove);
+    qtest_add_func("qmp/monitor-error-paths", test_qmp_monitor_error_paths);
 
     return g_test_run();
 }

-- 
2.47.3
Re: [PATCH 4/5] tests/qtest: add tests for dynamic monitor add/remove
Posted by Thomas Huth 6 days ago
Am Thu, 02 Apr 2026 23:19:19 +0200
schrieb Christian Brauner <brauner@kernel.org>:

> Test the monitor-add, monitor-remove, and query-monitors QMP commands:
> 
> - Basic lifecycle: chardev-add -> monitor-add -> query-monitors ->
>   monitor-remove -> chardev-remove
> - Error: duplicate monitor id
> - Error: monitor-remove on nonexistent id
> - Error: monitor-add with nonexistent chardev
> - Re-add after remove: same id and chardev reusable after removal
> 
> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
> ---
>  tests/qtest/qmp-test.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 101 insertions(+)
> 
> diff --git a/tests/qtest/qmp-test.c b/tests/qtest/qmp-test.c
> index edf0886787..9dbd3a6103 100644
> --- a/tests/qtest/qmp-test.c
> +++ b/tests/qtest/qmp-test.c
> @@ -337,6 +337,105 @@ static void test_qmp_missing_any_arg(void)
>      qtest_quit(qts);
>  }
>  
> +static void test_qmp_monitor_add_remove(void)
> +{
> +    QTestState *qts;
> +    QDict *resp;
> +
> +    qts = qtest_init(common_args);
> +
> +    /* Create a null chardev for the dynamic monitor */
> +    resp = qtest_qmp(qts,
> +                     "{'execute': 'chardev-add',"
> +                     " 'arguments': {'id': 'monitor-chardev',"
> +                     "               'backend': {'type': 'null',"
> +                     "                           'data': {}}}}");
> +    g_assert(qdict_haskey(resp, "return"));
> +    qobject_unref(resp);
> +
> +    /* Add a dynamic monitor */
> +    resp = qtest_qmp(qts,
> +                     "{'execute': 'monitor-add',"
> +                     " 'arguments': {'id': 'dyn-mon',"
> +                     "               'chardev': 'monitor-chardev'}}");
> +    g_assert(qdict_haskey(resp, "return"));
> +    qobject_unref(resp);
> +
> +    /* Verify it shows up in query-monitors */
> +    resp = qtest_qmp(qts, "{'execute': 'query-monitors'}");
> +    g_assert(!qdict_haskey(resp, "error"));
> +    qobject_unref(resp);
> +
> +    /* Error: duplicate id */
> +    resp = qtest_qmp(qts,
> +                     "{'execute': 'monitor-add',"
> +                     " 'arguments': {'id': 'dyn-mon',"
> +                     "               'chardev': 'monitor-chardev'}}");
> +    qmp_expect_error_and_unref(resp, "GenericError");
> +
> +    /* Remove the dynamic monitor */
> +    resp = qtest_qmp(qts,
> +                     "{'execute': 'monitor-remove',"
> +                     " 'arguments': {'id': 'dyn-mon'}}");
> +    g_assert(qdict_haskey(resp, "return"));
> +    qobject_unref(resp);
> +
> +    /* Error: remove nonexistent */
> +    resp = qtest_qmp(qts,
> +                     "{'execute': 'monitor-remove',"
> +                     " 'arguments': {'id': 'dyn-mon'}}");
> +    qmp_expect_error_and_unref(resp, "GenericError");
> +
> +    /* Error: remove CLI monitor (the default one) -- find its id first.
> +     * CLI monitors typically have no id, so use a bogus id to test. */

Please check coding style with scripts/checkpatch.pl - I guess it will
complain about the multiline comment here.

Apart from that, the patch looks fine to me. But I think either a qtest or
a functional test should be enough, you don't need both. I'd maybe
recommend to just keep the qtest, since these tests are often run more
frequently than the functional tests.

 Thomas
Re: [PATCH 4/5] tests/qtest: add tests for dynamic monitor add/remove
Posted by Christian Brauner 5 days, 4 hours ago
On Sun, Apr 05, 2026 at 06:11:35PM +0000, Thomas Huth wrote:
> Am Thu, 02 Apr 2026 23:19:19 +0200
> schrieb Christian Brauner <brauner@kernel.org>:
> 
> > Test the monitor-add, monitor-remove, and query-monitors QMP commands:
> > 
> > - Basic lifecycle: chardev-add -> monitor-add -> query-monitors ->
> >   monitor-remove -> chardev-remove
> > - Error: duplicate monitor id
> > - Error: monitor-remove on nonexistent id
> > - Error: monitor-add with nonexistent chardev
> > - Re-add after remove: same id and chardev reusable after removal
> > 
> > Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
> > ---
> >  tests/qtest/qmp-test.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 101 insertions(+)
> > 
> > diff --git a/tests/qtest/qmp-test.c b/tests/qtest/qmp-test.c
> > index edf0886787..9dbd3a6103 100644
> > --- a/tests/qtest/qmp-test.c
> > +++ b/tests/qtest/qmp-test.c
> > @@ -337,6 +337,105 @@ static void test_qmp_missing_any_arg(void)
> >      qtest_quit(qts);
> >  }
> >  
> > +static void test_qmp_monitor_add_remove(void)
> > +{
> > +    QTestState *qts;
> > +    QDict *resp;
> > +
> > +    qts = qtest_init(common_args);
> > +
> > +    /* Create a null chardev for the dynamic monitor */
> > +    resp = qtest_qmp(qts,
> > +                     "{'execute': 'chardev-add',"
> > +                     " 'arguments': {'id': 'monitor-chardev',"
> > +                     "               'backend': {'type': 'null',"
> > +                     "                           'data': {}}}}");
> > +    g_assert(qdict_haskey(resp, "return"));
> > +    qobject_unref(resp);
> > +
> > +    /* Add a dynamic monitor */
> > +    resp = qtest_qmp(qts,
> > +                     "{'execute': 'monitor-add',"
> > +                     " 'arguments': {'id': 'dyn-mon',"
> > +                     "               'chardev': 'monitor-chardev'}}");
> > +    g_assert(qdict_haskey(resp, "return"));
> > +    qobject_unref(resp);
> > +
> > +    /* Verify it shows up in query-monitors */
> > +    resp = qtest_qmp(qts, "{'execute': 'query-monitors'}");
> > +    g_assert(!qdict_haskey(resp, "error"));
> > +    qobject_unref(resp);
> > +
> > +    /* Error: duplicate id */
> > +    resp = qtest_qmp(qts,
> > +                     "{'execute': 'monitor-add',"
> > +                     " 'arguments': {'id': 'dyn-mon',"
> > +                     "               'chardev': 'monitor-chardev'}}");
> > +    qmp_expect_error_and_unref(resp, "GenericError");
> > +
> > +    /* Remove the dynamic monitor */
> > +    resp = qtest_qmp(qts,
> > +                     "{'execute': 'monitor-remove',"
> > +                     " 'arguments': {'id': 'dyn-mon'}}");
> > +    g_assert(qdict_haskey(resp, "return"));
> > +    qobject_unref(resp);
> > +
> > +    /* Error: remove nonexistent */
> > +    resp = qtest_qmp(qts,
> > +                     "{'execute': 'monitor-remove',"
> > +                     " 'arguments': {'id': 'dyn-mon'}}");
> > +    qmp_expect_error_and_unref(resp, "GenericError");
> > +
> > +    /* Error: remove CLI monitor (the default one) -- find its id first.
> > +     * CLI monitors typically have no id, so use a bogus id to test. */
> 
> Please check coding style with scripts/checkpatch.pl - I guess it will
> complain about the multiline comment here.

Thanks, whatever checkpatch.pl raised should now be fixed.

> Apart from that, the patch looks fine to me. But I think either a qtest or
> a functional test should be enough, you don't need both. I'd maybe
> recommend to just keep the qtest, since these tests are often run more
> frequently than the functional tests.

Hm, I did keep both for v2 and I think whoever applies the changes (if
accepted) can just decide which patch to drop so I'm inclined to just
keep it.