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
- Error: second monitor on same chardev (chardev already in use)
- Error: monitor-remove on CLI-created monitor
- Error: monitor-remove on HMP monitor
- 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 | 185 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 185 insertions(+)
diff --git a/tests/qtest/qmp-test.c b/tests/qtest/qmp-test.c
index edf0886787..a493a812a9 100644
--- a/tests/qtest/qmp-test.c
+++ b/tests/qtest/qmp-test.c
@@ -337,6 +337,186 @@ 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");
+
+ /* 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);
+}
+
+static void test_qmp_monitor_chardev_in_use(void)
+{
+ QTestState *qts;
+ QDict *resp;
+
+ qts = qtest_init(common_args);
+
+ /* Create a null chardev */
+ resp = qtest_qmp(qts,
+ "{'execute': 'chardev-add',"
+ " 'arguments': {'id': 'shared-chr',"
+ " 'backend': {'type': 'null',"
+ " 'data': {}}}}");
+ g_assert(qdict_haskey(resp, "return"));
+ qobject_unref(resp);
+
+ /* Attach first monitor */
+ resp = qtest_qmp(qts,
+ "{'execute': 'monitor-add',"
+ " 'arguments': {'id': 'mon-1',"
+ " 'chardev': 'shared-chr'}}");
+ g_assert(qdict_haskey(resp, "return"));
+ qobject_unref(resp);
+
+ /* Error: second monitor on the same chardev */
+ resp = qtest_qmp(qts,
+ "{'execute': 'monitor-add',"
+ " 'arguments': {'id': 'mon-2',"
+ " 'chardev': 'shared-chr'}}");
+ qmp_expect_error_and_unref(resp, "GenericError");
+
+ /* Clean up */
+ resp = qtest_qmp(qts,
+ "{'execute': 'monitor-remove',"
+ " 'arguments': {'id': 'mon-1'}}");
+ g_assert(qdict_haskey(resp, "return"));
+ qobject_unref(resp);
+
+ resp = qtest_qmp(qts,
+ "{'execute': 'chardev-remove',"
+ " 'arguments': {'id': 'shared-chr'}}");
+ g_assert(qdict_haskey(resp, "return"));
+ qobject_unref(resp);
+
+ qtest_quit(qts);
+}
+
+static void test_qmp_monitor_remove_cli(void)
+{
+ QTestState *qts;
+ QDict *resp;
+
+ /* Launch with a named CLI monitor on a null chardev */
+ qts = qtest_initf("%s -chardev null,id=cli-chr"
+ " -mon id=cli-mon,chardev=cli-chr,mode=control",
+ common_args);
+
+ /* Error: monitor-remove must reject CLI-created monitors */
+ resp = qtest_qmp(qts,
+ "{'execute': 'monitor-remove',"
+ " 'arguments': {'id': 'cli-mon'}}");
+ qmp_expect_error_and_unref(resp, "GenericError");
+
+ qtest_quit(qts);
+}
+
+static void test_qmp_monitor_remove_hmp(void)
+{
+ QTestState *qts;
+ QDict *resp;
+
+ qts = qtest_initf("%s -chardev null,id=hmp-chr"
+ " -mon id=hmp-mon,chardev=hmp-chr,mode=readline",
+ common_args);
+
+ /* Error: monitor-remove must reject HMP monitors */
+ resp = qtest_qmp(qts,
+ "{'execute': 'monitor-remove',"
+ " 'arguments': {'id': 'hmp-mon'}}");
+ qmp_expect_error_and_unref(resp, "GenericError");
+
+ qtest_quit(qts);
+}
+
int main(int argc, char *argv[])
{
g_test_init(&argc, &argv, NULL);
@@ -348,6 +528,11 @@ 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);
+ qtest_add_func("qmp/monitor-chardev-in-use", test_qmp_monitor_chardev_in_use);
+ qtest_add_func("qmp/monitor-remove-cli", test_qmp_monitor_remove_cli);
+ qtest_add_func("qmp/monitor-remove-hmp", test_qmp_monitor_remove_hmp);
return g_test_run();
}
--
2.47.3
© 2016 - 2026 Red Hat, Inc.