From 91fa93e516d080d440ead2ad4f88960545bd5b2c Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 18 Mar 2021 16:55:11 +0100 Subject: qapi: Implement deprecated-output=hide for QMP command results This policy suppresses deprecated bits in output, and thus permits "testing the future". Implement it for QMP command results. Example: when QEMU is run with -compat deprecated-output=hide, then {"execute": "query-cpus-fast"} yields {"return": [{"thread-id": 9805, "props": {"core-id": 0, "thread-id": 0, "socket-id": 0}, "qom-path": "/machine/unattached/device[0]", "cpu-index": 0, "target": "x86_64"}]} instead of {"return": [{"arch": "x86", "thread-id": 22436, "props": {"core-id": 0, "thread-id": 0, "socket-id": 0}, "qom-path": "/machine/unattached/device[0]", "cpu-index": 0, "target": "x86_64"}]} Note the suppression of deprecated member "arch". Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20210318155519.1224118-4-armbru@redhat.com> --- tests/qapi-schema/qapi-schema-test.json | 17 ++++++------- tests/qapi-schema/qapi-schema-test.out | 18 +++++++------- tests/unit/test-qmp-cmds.c | 42 +++++++++++++++++++++++++++++---- 3 files changed, 55 insertions(+), 22 deletions(-) (limited to 'tests') diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json index 63f92ad..48a0ada 100644 --- a/tests/qapi-schema/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -299,14 +299,15 @@ 'features': [ 'feature1' ] } { 'command': 'test-features0', - 'data': { 'fs0': 'FeatureStruct0', - 'fs1': 'FeatureStruct1', - 'fs2': 'FeatureStruct2', - 'fs3': 'FeatureStruct3', - 'fs4': 'FeatureStruct4', - 'cfs1': 'CondFeatureStruct1', - 'cfs2': 'CondFeatureStruct2', - 'cfs3': 'CondFeatureStruct3' }, + 'data': { '*fs0': 'FeatureStruct0', + '*fs1': 'FeatureStruct1', + '*fs2': 'FeatureStruct2', + '*fs3': 'FeatureStruct3', + '*fs4': 'FeatureStruct4', + '*cfs1': 'CondFeatureStruct1', + '*cfs2': 'CondFeatureStruct2', + '*cfs3': 'CondFeatureStruct3' }, + 'returns': 'FeatureStruct1', 'features': [] } { 'command': 'test-command-features1', diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out index 3b1387d..776d737 100644 --- a/tests/qapi-schema/qapi-schema-test.out +++ b/tests/qapi-schema/qapi-schema-test.out @@ -409,15 +409,15 @@ alternate FeatureAlternate1 case eins: FeatureStruct1 feature feature1 object q_obj_test-features0-arg - member fs0: FeatureStruct0 optional=False - member fs1: FeatureStruct1 optional=False - member fs2: FeatureStruct2 optional=False - member fs3: FeatureStruct3 optional=False - member fs4: FeatureStruct4 optional=False - member cfs1: CondFeatureStruct1 optional=False - member cfs2: CondFeatureStruct2 optional=False - member cfs3: CondFeatureStruct3 optional=False -command test-features0 q_obj_test-features0-arg -> None + member fs0: FeatureStruct0 optional=True + member fs1: FeatureStruct1 optional=True + member fs2: FeatureStruct2 optional=True + member fs3: FeatureStruct3 optional=True + member fs4: FeatureStruct4 optional=True + member cfs1: CondFeatureStruct1 optional=True + member cfs2: CondFeatureStruct2 optional=True + member cfs3: CondFeatureStruct3 optional=True +command test-features0 q_obj_test-features0-arg -> FeatureStruct1 gen=True success_response=True boxed=False oob=False preconfig=False command test-command-features1 None -> None gen=True success_response=True boxed=False oob=False preconfig=False diff --git a/tests/unit/test-qmp-cmds.c b/tests/unit/test-qmp-cmds.c index d3413bf..1079d35 100644 --- a/tests/unit/test-qmp-cmds.c +++ b/tests/unit/test-qmp-cmds.c @@ -1,4 +1,5 @@ #include "qemu/osdep.h" +#include "qapi/compat-policy.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qjson.h" #include "qapi/qmp/qnum.h" @@ -49,12 +50,17 @@ void qmp_user_def_cmd1(UserDefOne * ud1, Error **errp) { } -void qmp_test_features0(FeatureStruct0 *fs0, FeatureStruct1 *fs1, - FeatureStruct2 *fs2, FeatureStruct3 *fs3, - FeatureStruct4 *fs4, CondFeatureStruct1 *cfs1, - CondFeatureStruct2 *cfs2, CondFeatureStruct3 *cfs3, - Error **errp) +FeatureStruct1 *qmp_test_features0(bool has_fs0, FeatureStruct0 *fs0, + bool has_fs1, FeatureStruct1 *fs1, + bool has_fs2, FeatureStruct2 *fs2, + bool has_fs3, FeatureStruct3 *fs3, + bool has_fs4, FeatureStruct4 *fs4, + bool has_cfs1, CondFeatureStruct1 *cfs1, + bool has_cfs2, CondFeatureStruct2 *cfs2, + bool has_cfs3, CondFeatureStruct3 *cfs3, + Error **errp) { + return g_new0(FeatureStruct1, 1); } void qmp_test_command_features1(Error **errp) @@ -275,6 +281,30 @@ static void test_dispatch_cmd_io(void) qobject_unref(ret3); } +static void test_dispatch_cmd_ret_deprecated(void) +{ + const char *cmd = "{ 'execute': 'test-features0' }"; + QDict *ret; + + memset(&compat_policy, 0, sizeof(compat_policy)); + + /* default accept */ + ret = qobject_to(QDict, do_qmp_dispatch(false, cmd)); + assert(ret && qdict_size(ret) == 1); + qobject_unref(ret); + + compat_policy.has_deprecated_output = true; + compat_policy.deprecated_output = COMPAT_POLICY_OUTPUT_ACCEPT; + ret = qobject_to(QDict, do_qmp_dispatch(false, cmd)); + assert(ret && qdict_size(ret) == 1); + qobject_unref(ret); + + compat_policy.deprecated_output = COMPAT_POLICY_OUTPUT_HIDE; + ret = qobject_to(QDict, do_qmp_dispatch(false, cmd)); + assert(ret && qdict_size(ret) == 0); + qobject_unref(ret); +} + /* test generated dealloc functions for generated types */ static void test_dealloc_types(void) { @@ -349,6 +379,8 @@ int main(int argc, char **argv) g_test_add_func("/qmp/dispatch_cmd_io", test_dispatch_cmd_io); g_test_add_func("/qmp/dispatch_cmd_success_response", test_dispatch_cmd_success_response); + g_test_add_func("/qmp/dispatch_cmd_ret_deprecated", + test_dispatch_cmd_ret_deprecated); g_test_add_func("/qmp/dealloc_types", test_dealloc_types); g_test_add_func("/qmp/dealloc_partial", test_dealloc_partial); -- cgit v1.1 From 278fc2f7d3425dfbc6aa91644bffc65e94afad7c Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 18 Mar 2021 16:55:12 +0100 Subject: qapi: Implement deprecated-output=hide for QMP events This policy suppresses deprecated bits in output, and thus permits "testing the future". Implement it for QMP events: suppress deprecated ones. No QMP event is deprecated right now. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20210318155519.1224118-5-armbru@redhat.com> --- tests/unit/test-qmp-event.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'tests') diff --git a/tests/unit/test-qmp-event.c b/tests/unit/test-qmp-event.c index 7dd0053..ab059fb 100644 --- a/tests/unit/test-qmp-event.c +++ b/tests/unit/test-qmp-event.c @@ -14,6 +14,7 @@ #include "qemu/osdep.h" #include "qemu-common.h" +#include "qapi/compat-policy.h" #include "qapi/error.h" #include "qapi/qmp/qbool.h" #include "qapi/qmp/qdict.h" @@ -140,6 +141,24 @@ static void test_event_d(TestEventData *data, qobject_unref(data->expect); } +static void test_event_deprecated(TestEventData *data, const void *unused) +{ + data->expect = qdict_from_jsonf_nofail("{ 'event': 'TEST-EVENT-FEATURES1' }"); + + memset(&compat_policy, 0, sizeof(compat_policy)); + + qapi_event_send_test_event_features1(); + g_assert(data->emitted); + + compat_policy.has_deprecated_output = true; + compat_policy.deprecated_output = COMPAT_POLICY_OUTPUT_HIDE; + data->emitted = false; + qapi_event_send_test_event_features1(); + g_assert(!data->emitted); + + qobject_unref(data->expect); +} + int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); @@ -148,6 +167,7 @@ int main(int argc, char **argv) event_test_add("/event/event_b", test_event_b); event_test_add("/event/event_c", test_event_c); event_test_add("/event/event_d", test_event_d); + event_test_add("/event/deprecated", test_event_deprecated); g_test_run(); return 0; -- cgit v1.1 From a291a38fa1db6a67bd9046da26a48e82c591ca49 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 18 Mar 2021 16:55:13 +0100 Subject: qapi: Implement deprecated-output=hide for QMP event data This policy suppresses deprecated bits in output, and thus permits "testing the future". Implement it for QMP event data: suppress deprecated members. No QMP event data is deprecated right now. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20210318155519.1224118-6-armbru@redhat.com> --- tests/qapi-schema/qapi-schema-test.json | 3 +++ tests/qapi-schema/qapi-schema-test.out | 2 ++ tests/unit/test-qmp-event.c | 21 +++++++++++++++++++++ 3 files changed, 26 insertions(+) (limited to 'tests') diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json index 48a0ada..12ec588 100644 --- a/tests/qapi-schema/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -324,5 +324,8 @@ 'features': [ { 'name': 'feature1', 'if': [ 'defined(TEST_IF_COND_1)', 'defined(TEST_IF_COND_2)'] } ] } +{ 'event': 'TEST-EVENT-FEATURES0', + 'data': 'FeatureStruct1' } + { 'event': 'TEST-EVENT-FEATURES1', 'features': [ 'deprecated' ] } diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out index 776d737..f5741df 100644 --- a/tests/qapi-schema/qapi-schema-test.out +++ b/tests/qapi-schema/qapi-schema-test.out @@ -440,6 +440,8 @@ command test-command-cond-features3 None -> None gen=True success_response=True boxed=False oob=False preconfig=False feature feature1 if ['defined(TEST_IF_COND_1)', 'defined(TEST_IF_COND_2)'] +event TEST-EVENT-FEATURES0 FeatureStruct1 + boxed=False event TEST-EVENT-FEATURES1 None boxed=False feature deprecated diff --git a/tests/unit/test-qmp-event.c b/tests/unit/test-qmp-event.c index ab059fb..047f44f 100644 --- a/tests/unit/test-qmp-event.c +++ b/tests/unit/test-qmp-event.c @@ -159,6 +159,26 @@ static void test_event_deprecated(TestEventData *data, const void *unused) qobject_unref(data->expect); } +static void test_event_deprecated_data(TestEventData *data, const void *unused) +{ + memset(&compat_policy, 0, sizeof(compat_policy)); + + data->expect = qdict_from_jsonf_nofail("{ 'event': 'TEST-EVENT-FEATURES0'," + " 'data': { 'foo': 42 } }"); + qapi_event_send_test_event_features0(42); + g_assert(data->emitted); + + qobject_unref(data->expect); + + compat_policy.has_deprecated_output = true; + compat_policy.deprecated_output = COMPAT_POLICY_OUTPUT_HIDE; + data->expect = qdict_from_jsonf_nofail("{ 'event': 'TEST-EVENT-FEATURES0' }"); + qapi_event_send_test_event_features0(42); + g_assert(data->emitted); + + qobject_unref(data->expect); +} + int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); @@ -168,6 +188,7 @@ int main(int argc, char **argv) event_test_add("/event/event_c", test_event_c); event_test_add("/event/event_d", test_event_d); event_test_add("/event/deprecated", test_event_deprecated); + event_test_add("/event/deprecated_data", test_event_deprecated_data); g_test_run(); return 0; -- cgit v1.1 From 130d4824222cf062ed8ee3c5ab9fa2bd852b33b6 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 18 Mar 2021 16:55:16 +0100 Subject: test-util-sockets: Add stub for monitor_set_cur() Without this stub, the next commit fails to link. I suspect the real cause is 947e47448d "monitor: Use getter/setter functions for cur_mon". Cc: Kevin Wolf Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20210318155519.1224118-9-armbru@redhat.com> --- tests/unit/test-util-sockets.c | 1 + 1 file changed, 1 insertion(+) (limited to 'tests') diff --git a/tests/unit/test-util-sockets.c b/tests/unit/test-util-sockets.c index 6748605..72b9246 100644 --- a/tests/unit/test-util-sockets.c +++ b/tests/unit/test-util-sockets.c @@ -73,6 +73,7 @@ int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp) * otherwise we get duplicate syms at link time. */ Monitor *monitor_cur(void) { return cur_mon; } +Monitor *monitor_set_cur(Coroutine *co, Monitor *mon) { abort(); } int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) { abort(); } #ifndef _WIN32 -- cgit v1.1 From d2032598c434fe385145ee6ea58007a19ef7e723 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 18 Mar 2021 16:55:17 +0100 Subject: qapi: Implement deprecated-input=reject for QMP commands This policy rejects deprecated input, and thus permits "testing the future". Implement it for QMP commands: make deprecated ones fail. Example: when QEMU is run with -compat deprecated-input=reject, then {"execute": "query-cpus"} fails like this {"error": {"class": "CommandNotFound", "desc": "Deprecated command query-cpus disabled by policy"}} When the deprecated command is removed, the error will change to {"error": {"class": "CommandNotFound", "desc": "The command query-cpus has not been found"}} Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20210318155519.1224118-10-armbru@redhat.com> --- tests/unit/test-qmp-cmds.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'tests') diff --git a/tests/unit/test-qmp-cmds.c b/tests/unit/test-qmp-cmds.c index 1079d35..cba9821 100644 --- a/tests/unit/test-qmp-cmds.c +++ b/tests/unit/test-qmp-cmds.c @@ -281,6 +281,28 @@ static void test_dispatch_cmd_io(void) qobject_unref(ret3); } +static void test_dispatch_cmd_deprecated(void) +{ + const char *cmd = "{ 'execute': 'test-command-features1' }"; + QDict *ret; + + memset(&compat_policy, 0, sizeof(compat_policy)); + + /* accept */ + ret = qobject_to(QDict, do_qmp_dispatch(false, cmd)); + assert(ret && qdict_size(ret) == 0); + qobject_unref(ret); + + compat_policy.has_deprecated_input = true; + compat_policy.deprecated_input = COMPAT_POLICY_INPUT_ACCEPT; + ret = qobject_to(QDict, do_qmp_dispatch(false, cmd)); + assert(ret && qdict_size(ret) == 0); + qobject_unref(ret); + + compat_policy.deprecated_input = COMPAT_POLICY_INPUT_REJECT; + do_qmp_dispatch_error(false, ERROR_CLASS_COMMAND_NOT_FOUND, cmd); +} + static void test_dispatch_cmd_ret_deprecated(void) { const char *cmd = "{ 'execute': 'test-features0' }"; @@ -379,6 +401,8 @@ int main(int argc, char **argv) g_test_add_func("/qmp/dispatch_cmd_io", test_dispatch_cmd_io); g_test_add_func("/qmp/dispatch_cmd_success_response", test_dispatch_cmd_success_response); + g_test_add_func("/qmp/dispatch_cmd_deprecated", + test_dispatch_cmd_deprecated); g_test_add_func("/qmp/dispatch_cmd_ret_deprecated", test_dispatch_cmd_ret_deprecated); g_test_add_func("/qmp/dealloc_types", test_dealloc_types); -- cgit v1.1 From db29164103e53ae7c112086127e3d1c92b1d4d89 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 18 Mar 2021 16:55:18 +0100 Subject: qapi: Implement deprecated-input=reject for QMP command arguments This policy rejects deprecated input, and thus permits "testing the future". Implement it for QMP command arguments: reject commands with deprecated ones. Example: when QEMU is run with -compat deprecated-input=reject, then {"execute": "eject", "arguments": {"device": "cd"}} fails like this {"error": {"class": "GenericError", "desc": "Deprecated parameter 'device' disabled by policy"}} When the deprecated parameter is removed, the error will change to {"error": {"class": "GenericError", "desc": "Parameter 'device' is unexpected"}} Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <20210318155519.1224118-11-armbru@redhat.com> --- tests/unit/test-qmp-cmds.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'tests') diff --git a/tests/unit/test-qmp-cmds.c b/tests/unit/test-qmp-cmds.c index cba9821..266db07 100644 --- a/tests/unit/test-qmp-cmds.c +++ b/tests/unit/test-qmp-cmds.c @@ -303,6 +303,29 @@ static void test_dispatch_cmd_deprecated(void) do_qmp_dispatch_error(false, ERROR_CLASS_COMMAND_NOT_FOUND, cmd); } +static void test_dispatch_cmd_arg_deprecated(void) +{ + const char *cmd = "{ 'execute': 'test-features0'," + " 'arguments': { 'fs1': { 'foo': 42 } } }"; + QDict *ret; + + memset(&compat_policy, 0, sizeof(compat_policy)); + + /* accept */ + ret = qobject_to(QDict, do_qmp_dispatch(false, cmd)); + assert(ret && qdict_size(ret) == 1); + qobject_unref(ret); + + compat_policy.has_deprecated_input = true; + compat_policy.deprecated_input = COMPAT_POLICY_INPUT_ACCEPT; + ret = qobject_to(QDict, do_qmp_dispatch(false, cmd)); + assert(ret && qdict_size(ret) == 1); + qobject_unref(ret); + + compat_policy.deprecated_input = COMPAT_POLICY_INPUT_REJECT; + do_qmp_dispatch_error(false, ERROR_CLASS_GENERIC_ERROR, cmd); +} + static void test_dispatch_cmd_ret_deprecated(void) { const char *cmd = "{ 'execute': 'test-features0' }"; @@ -403,6 +426,8 @@ int main(int argc, char **argv) test_dispatch_cmd_success_response); g_test_add_func("/qmp/dispatch_cmd_deprecated", test_dispatch_cmd_deprecated); + g_test_add_func("/qmp/dispatch_cmd_arg_deprecated", + test_dispatch_cmd_arg_deprecated); g_test_add_func("/qmp/dispatch_cmd_ret_deprecated", test_dispatch_cmd_ret_deprecated); g_test_add_func("/qmp/dealloc_types", test_dealloc_types); -- cgit v1.1