From: Christian Brauner <brauner@kernel.org>
Test the object-add/object-del QMP commands with the monitor-qmp
object type.
- Basic lifecycle: chardev-add -> object-add -> object-del -> chardev-remove
- Error: object-add with nonexistent chardev
- Error: second monitor on same chardev (chardev already in use)
- Removal of CLI-created QMP monitor succeeds
- Error: object-remove on HMP monitor
- Re-add after remove: same id and chardev reusable after removal
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
[DB: modified to use object-add/object-del, removing redundant
scenarios already handled by object-add/del code]
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Tested-by: Peter Krempa <pkrempa@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
tests/qtest/qmp-test.c | 174 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 174 insertions(+)
diff --git a/tests/qtest/qmp-test.c b/tests/qtest/qmp-test.c
index edf0886787..3a325a04e0 100644
--- a/tests/qtest/qmp-test.c
+++ b/tests/qtest/qmp-test.c
@@ -337,6 +337,174 @@ 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': 'object-add',"
+ " 'arguments': {'qom-type': 'monitor-qmp',"
+ " 'id': 'dyn-mon',"
+ " 'chardev': 'monitor-chardev'}}");
+ g_assert(qdict_haskey(resp, "return"));
+ qobject_unref(resp);
+
+ /* Remove the dynamic monitor */
+ resp = qtest_qmp(qts,
+ "{'execute': 'object-del',"
+ " 'arguments': {'id': 'dyn-mon'}}");
+ g_assert(qdict_haskey(resp, "return"));
+ qobject_unref(resp);
+
+ /* Add again after remove -- same id and chardev should work */
+ resp = qtest_qmp(qts,
+ "{'execute': 'object-add',"
+ " 'arguments': {'qom-type': 'monitor-qmp',"
+ " 'id': 'dyn-mon',"
+ " 'chardev': 'monitor-chardev'}}");
+ g_assert(qdict_haskey(resp, "return"));
+ qobject_unref(resp);
+
+ /* Clean up */
+ resp = qtest_qmp(qts,
+ "{'execute': 'object-del',"
+ " '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': 'object-add',"
+ " 'arguments': {'qom-type': 'monitor-qmp',"
+ " 'id': 'bad-mon',"
+ " 'chardev': 'nonexistent'}}");
+ 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': 'object-add',"
+ " 'arguments': {'qom-type': 'monitor-qmp',"
+ " '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': 'object-add',"
+ " 'arguments': {'qom-type': 'monitor-qmp',"
+ " 'id': 'mon-2',"
+ " 'chardev': 'shared-chr'}}");
+ qmp_expect_error_and_unref(resp, "GenericError");
+
+ /* Clean up */
+ resp = qtest_qmp(qts,
+ "{'execute': 'object-del',"
+ " '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"
+ " -object monitor-qmp,id=cli-mon,chardev=cli-chr",
+ common_args);
+
+ /* CLI-created QMP monitors can be removed */
+ resp = qtest_qmp(qts,
+ "{'execute': 'object-del',"
+ " 'arguments': {'id': 'cli-mon'}}");
+ g_assert(qdict_haskey(resp, "return"));
+ qobject_unref(resp);
+
+ resp = qtest_qmp(qts,
+ "{'execute': 'chardev-remove',"
+ " 'arguments': {'id': 'cli-chr'}}");
+ g_assert(qdict_haskey(resp, "return"));
+ qobject_unref(resp);
+
+ qtest_quit(qts);
+}
+
+static void test_qmp_monitor_remove_hmp(void)
+{
+ QTestState *qts;
+ QDict *resp;
+
+ qts = qtest_initf("%s -chardev null,id=hmp-chr"
+ " -object monitor-hmp,id=hmp-mon,chardev=hmp-chr",
+ common_args);
+
+ /* Error: object_del must reject HMP monitors */
+ resp = qtest_qmp(qts,
+ "{'execute': 'object-del',"
+ " '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 +516,12 @@ 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.55.0