[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 12/12] [NOT FOR MERGE] tests/qtest: Introduce qtest_validate_args
From: |
Fabiano Rosas |
Subject: |
[PATCH 12/12] [NOT FOR MERGE] tests/qtest: Introduce qtest_validate_args |
Date: |
Mon, 6 Feb 2023 12:04:16 -0300 |
The QEMU binary can be built with a varied set of features/devices
which are opaque to the tests. Add a centralized point for parsing and
validating the command line.
Tests can now be skipped with the following pattern:
qts = qtest_init(args);
if (!qts) {
return;
}
For now, the only validation is that the -device options all
correspond to devices that are actually present in the build.
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
Would this be better than checking for missing devices in individual
tests?
---
tests/qtest/libqtest.c | 137 ++++++++++++++++++++++++++++++++++++++++-
tests/qtest/libqtest.h | 12 ++++
2 files changed, 148 insertions(+), 1 deletion(-)
diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c
index d658222a19..7920fd1506 100644
--- a/tests/qtest/libqtest.c
+++ b/tests/qtest/libqtest.c
@@ -479,10 +479,145 @@ QTestState *qtest_init_without_qmp_handshake(const char
*extra_args)
return s;
}
+enum qemu_options {
+ DEVICE = G_TOKEN_LAST + 1,
+ DRIVER = G_TOKEN_LAST + 2,
+};
+
+static void _add_option(GHashTable *ht, const char *key, const char *val)
+{
+ GList *list = g_hash_table_lookup(ht, key);
+
+ if (!list) {
+ list = g_list_append(list, g_strdup(val));
+ g_hash_table_insert(ht, g_strdup(key), list);
+ } else {
+ list = g_list_append(list, g_strdup(val));
+ }
+}
+
+static void _parse_device_json(GHashTable *opts, GScanner *top_scanner)
+{
+ GScanner *scanner = g_scanner_new(top_scanner->config);
+ gchar *text;
+
+ assert(top_scanner->token == G_TOKEN_STRING);
+ text = g_strdup(top_scanner->value.v_string);
+
+ g_scanner_scope_add_symbol(scanner, 0, "driver", GINT_TO_POINTER(DRIVER));
+ g_scanner_input_text(scanner, text, strlen(text));
+
+ do {
+ g_scanner_get_next_token(scanner);
+ switch ((enum qemu_options)scanner->token) {
+ case DRIVER:
+ /* -device "{'driver':'dev' */
+ g_scanner_get_next_token(scanner);
+
+ switch (scanner->token) {
+ case G_TOKEN_IDENTIFIER:
+ _add_option(opts, "devices", scanner->value.v_string);
+ break;
+
+ default: /* invalid */
+ _add_option(opts, "devices", NULL);
+ }
+ break;
+ default:
+ break;
+ }
+ g_scanner_peek_next_token(scanner);
+ } while (scanner->next_token != G_TOKEN_EOF &&
+ scanner->next_token != G_TOKEN_ERROR);
+
+ g_scanner_destroy(scanner);
+ g_free(text);
+}
+
+static void qtest_parse_args(GHashTable *opts, const char *args)
+{
+ GScanner *scanner = g_scanner_new(NULL);
+
+ scanner->input_name = "qtest args";
+ scanner->config->symbol_2_token = 1;
+ scanner->config->scan_float = 0;
+ scanner->config->scan_string_sq = 0;
+ scanner->config->cset_skip_characters = g_strdup(" \t\n':");
+ scanner->config->cset_identifier_first = g_strdup("-" G_CSET_a_2_z
+ G_CSET_A_2_Z
+ G_CSET_DIGITS),
+ scanner->config->cset_identifier_nth = g_strdup("-_." G_CSET_a_2_z
+ G_CSET_A_2_Z
G_CSET_DIGITS),
+
+ g_scanner_scope_add_symbol(scanner, 0, "-device", GINT_TO_POINTER(DEVICE));
+
+ g_scanner_input_text(scanner, args, strlen(args));
+
+ do {
+ g_scanner_get_next_token(scanner);
+
+ switch ((enum qemu_options)scanner->token) {
+ case DEVICE:
+ g_scanner_get_next_token(scanner);
+
+ switch (scanner->token) {
+ case G_TOKEN_IDENTIFIER: /* -device dev */
+ _add_option(opts, "devices", scanner->value.v_string);
+ break;
+
+ case G_TOKEN_STRING: /* -device "{'driver':'dev' */
+ _parse_device_json(opts, scanner);
+ break;
+
+ default: /* invalid */
+ _add_option(opts, "devices", NULL);
+ }
+ break;
+ default:
+ break;
+ }
+ g_scanner_peek_next_token(scanner);
+ } while (scanner->next_token != G_TOKEN_EOF &&
+ scanner->next_token != G_TOKEN_ERROR);
+
+ g_scanner_destroy(scanner);
+}
+
+bool qtest_validate_args(const char *args, char **msg)
+{
+ GHashTable *opts = g_hash_table_new(g_str_hash, g_str_equal);
+ GList *l;
+ bool rc = true;
+
+ qtest_parse_args(opts, args);
+
+ for (l = g_hash_table_lookup(opts, "devices"); l != NULL; l = l->next) {
+ if (!l->data || !qtest_has_device(l->data)) {
+ *msg = g_strdup_printf("Device %s is not available",
+ (char *)l->data);
+ rc = false;
+ break;
+ }
+ }
+ g_hash_table_unref(opts);
+ return rc;
+}
+
QTestState *qtest_init(const char *extra_args)
{
- QTestState *s = qtest_init_without_qmp_handshake(extra_args);
+ QTestState *s;
QDict *greeting;
+/*
+ * char *err_msg;
+ *
+ * if (!qtest_validate_args(extra_args, &err_msg)) {
+ * g_test_skip(err_msg);
+ * g_free(err_msg);
+ *
+ * return NULL;
+ * }
+ */
+ s = qtest_init_without_qmp_handshake(extra_args);
/* Read the QMP greeting and then do the handshake */
greeting = qtest_qmp_receive(s);
diff --git a/tests/qtest/libqtest.h b/tests/qtest/libqtest.h
index fcf1c3c3b3..01a07c448a 100644
--- a/tests/qtest/libqtest.h
+++ b/tests/qtest/libqtest.h
@@ -832,4 +832,16 @@ void qtest_qom_set_bool(QTestState *s, const char *path,
const char *property,
* Returns: Value retrieved from property.
*/
bool qtest_qom_get_bool(QTestState *s, const char *path, const char *property);
+
+/**
+ * qtest_validate_args:
+ * @args: arguments to validate, exactly as they would be passed
+ * into qtest_init.
+ * @err_msg: String with the reason for the failure, if any.
+ *
+ * Validates the command line (args) for options that are incompatible
+ * with the current QEMU build.
+ */
+bool qtest_validate_args(const char *args, char **err_msg);
+
#endif
--
2.35.3
- Re: [PATCH 08/12] tests/qtest: Check for devices in bios-tables-test, (continued)
[PATCH 12/12] [NOT FOR MERGE] tests/qtest: Introduce qtest_validate_args,
Fabiano Rosas <=