* Re: [LTP] metadata: add tests grouping support
2026-06-12 13:54 [LTP] [PATCH 1/2] metadata: add tests grouping support Andrea Cervesato
@ 2026-06-12 19:10 ` linuxtestproject.agent
0 siblings, 0 replies; 5+ messages in thread
From: linuxtestproject.agent @ 2026-06-12 19:10 UTC (permalink / raw)
To: Andrea Cervesato; +Cc: ltp
Hi Andrea,
On 2026-06-12, Andrea Cervesato wrote:
> metadata: add tests grouping support
--- [PATCH 1/2] ---
> 2. @group tags in the doc comment block, e.g.:
> /* * Test description.
> *
> * @group stress
> */
The example appears malformed. metaparse only extracts @group tags
from doc comment blocks opened with /*\, not plain /* comments.
The test file (groups.c) correctly uses /*\ as the opening.
Should this be:
/*\
* Test description.
*
* @group stress
*/
Verdict - Needs revision
---
Note:
The agent can sometimes produce false positives although often its
findings are genuine. If you find issues with the review, please
comment this email or ignore the suggestions.
Regards,
LTP AI Reviewer
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 5+ messages in thread
* [LTP] [PATCH v2 0/2] Support metadata groups
@ 2026-06-18 14:10 Andrea Cervesato
2026-06-18 14:10 ` [LTP] [PATCH v2 1/2] metadata: add tests grouping support Andrea Cervesato
2026-06-18 14:10 ` [LTP] [PATCH v2 2/2] doc: conf.py: Show groups in test catalog Andrea Cervesato
0 siblings, 2 replies; 5+ messages in thread
From: Andrea Cervesato @ 2026-06-18 14:10 UTC (permalink / raw)
To: Linux Test Project
Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
Changes in v2:
- switch from @group to @groups
- use Cyril snippet to folter out groups from description
- optimize code
- Link to v1: https://lore.kernel.org/r/20260612-metadata_groups-v1-0-d7a24a7ac7a8@suse.com
---
Andrea Cervesato (2):
metadata: add tests grouping support
doc: conf.py: Show groups in test catalog
doc/conf.py | 10 +++
metadata/metaparse.c | 159 +++++++++++++++++++++++++++++++++++--------
metadata/tests/groups.c | 11 +++
metadata/tests/groups.c.json | 12 ++++
4 files changed, 162 insertions(+), 30 deletions(-)
---
base-commit: bc9cfca5c7b6599e501d580bb42b9538390fd9a6
change-id: 20260612-metadata_groups-dd2430e21901
Best regards,
--
Andrea Cervesato <andrea.cervesato@suse.com>
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 5+ messages in thread
* [LTP] [PATCH v2 1/2] metadata: add tests grouping support
2026-06-18 14:10 [LTP] [PATCH v2 0/2] Support metadata groups Andrea Cervesato
@ 2026-06-18 14:10 ` Andrea Cervesato
2026-06-18 16:40 ` [LTP] " linuxtestproject.agent
2026-06-18 14:10 ` [LTP] [PATCH v2 2/2] doc: conf.py: Show groups in test catalog Andrea Cervesato
1 sibling, 1 reply; 5+ messages in thread
From: Andrea Cervesato @ 2026-06-18 14:10 UTC (permalink / raw)
To: Linux Test Project
From: Andrea Cervesato <andrea.cervesato@suse.com>
Add groups field to metaparse JSON output, so we can filter out tests
in kirk. Groups are derived from:
1. Source file path - the two nearest parent directories (immediate
parent first), skipping 'kernel' as too generic. For example:
- testcases/kernel/syscalls/clone/clone01.c -> clone, syscalls
- testcases/kernel/kvm/kvm_pagefault01.c -> kvm
- testcases/cve/cve-2017-16939.c -> cve
2. @groups tags in the doc comment block, e.g.:
/*\
* Test description.
*
* @groups stress syscalls
* @groups memory
*/
Add test case for @groups tag parsing.
Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
metadata/metaparse.c | 159 +++++++++++++++++++++++++++++++++++--------
metadata/tests/groups.c | 11 +++
metadata/tests/groups.c.json | 12 ++++
3 files changed, 152 insertions(+), 30 deletions(-)
diff --git a/metadata/metaparse.c b/metadata/metaparse.c
index 561cbb9d2d54689988c9aa49d591628696bcf847..94e795c275aebda41737558d06f7d9c8c1a2f4f7 100644
--- a/metadata/metaparse.c
+++ b/metadata/metaparse.c
@@ -17,6 +17,7 @@
#include "data_storage.h"
#define INCLUDE_PATH_MAX 5
+#define GROUPS_TAG "groups"
static int verbose;
static char *cmdline_includepath[INCLUDE_PATH_MAX];
@@ -50,7 +51,49 @@ static const char *eat_asterisk_space(const char *c)
return c;
}
-static void multiline_comment(FILE *f, struct data_node *doc)
+/*
+ * Add a group to the groups array, skipping 'kernel' as it's too generic.
+ * Returns 0 if no group was added, 1 otherwise.
+ */
+static int add_group(struct data_node *groups, const char *name)
+{
+ if (name && strcmp(name, "kernel")) {
+ data_node_array_add(groups, data_node_string(name));
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Parse a '@groups foo bar baz' doc comment line, adding each
+ * whitespace-separated name to the groups array. Returns 1 if the line
+ * was a @groups tag (and should be consumed), 0 otherwise.
+ */
+static int parse_groups(struct data_node *groups, char *line)
+{
+ char *s;
+ char *name;
+
+ if (!groups)
+ return 0;
+
+ s = (char *)eat_asterisk_space(line);
+ if (strncmp(s, GROUPS_TAG, sizeof(GROUPS_TAG) - 1))
+ return 0;
+
+ s += sizeof(GROUPS_TAG) - 1;
+ if (*s && *s != ' ' && *s != '\t')
+ return 0;
+
+ for (name = strtok(s, " \t"); name; name = strtok(NULL, " \t"))
+ add_group(groups, name);
+
+ return 1;
+}
+
+static void multiline_comment(FILE *f, struct data_node *doc,
+ struct data_node *groups)
{
int c;
int state = 0;
@@ -62,12 +105,14 @@ static void multiline_comment(FILE *f, struct data_node *doc)
if (doc) {
if (c == '\n') {
- struct data_node *line;
+ char *str;
buf[bufp] = 0;
- line = data_node_string(eat_asterisk_space(buf));
- if (data_node_array_add(doc, line))
- WARN("doc string comment truncated");
+ str = (char *)eat_asterisk_space(buf);
bufp = 0;
+ if (parse_groups(groups, str))
+ continue;
+ if (data_node_array_add(doc, data_node_string(str)))
+ WARN("doc string comment truncated");
continue;
}
@@ -100,7 +145,8 @@ static void multiline_comment(FILE *f, struct data_node *doc)
static const char doc_prefix[] = "\\\n";
-static void maybe_doc_comment(FILE *f, struct data_node *doc)
+static void maybe_doc_comment(FILE *f, struct data_node *doc,
+ struct data_node *groups)
{
int c, i;
@@ -113,14 +159,15 @@ static void maybe_doc_comment(FILE *f, struct data_node *doc)
if (c == '*')
ungetc(c, f);
- multiline_comment(f, NULL);
+ multiline_comment(f, NULL, NULL);
return;
}
- multiline_comment(f, doc);
+ multiline_comment(f, doc, groups);
}
-static void maybe_comment(FILE *f, struct data_node *doc)
+static void maybe_comment(FILE *f, struct data_node *doc,
+ struct data_node *groups)
{
int c = getc(f);
@@ -129,7 +176,7 @@ static void maybe_comment(FILE *f, struct data_node *doc)
remove_to_newline(f);
break;
case '*':
- maybe_doc_comment(f, doc);
+ maybe_doc_comment(f, doc, groups);
break;
default:
ungetc(c, f);
@@ -137,7 +184,8 @@ static void maybe_comment(FILE *f, struct data_node *doc)
}
}
-static char *next_token2(FILE *f, char *buf, size_t buf_len, struct data_node *doc)
+static char *next_token2(FILE *f, char *buf, size_t buf_len,
+ struct data_node *doc, struct data_node *groups)
{
size_t i = 0;
int c;
@@ -194,7 +242,7 @@ static char *next_token2(FILE *f, char *buf, size_t buf_len, struct data_node *d
buf[i++] = c;
break;
case '/':
- maybe_comment(f, doc);
+ maybe_comment(f, doc, groups);
break;
case '"':
in_str = 1;
@@ -216,11 +264,11 @@ exit:
return buf;
}
-static char *next_token(FILE *f, struct data_node *doc)
+static char *next_token(FILE *f, struct data_node *doc, struct data_node *groups)
{
static char buf[4096];
- return next_token2(f, buf, sizeof(buf), doc);
+ return next_token2(f, buf, sizeof(buf), doc, groups);
}
static FILE *open_file(const char *dir, const char *fname)
@@ -383,7 +431,7 @@ static int array_is_hash(FILE *f)
int in_id = 1;
char *token;
- while ((token = next_token(f, NULL))) {
+ while ((token = next_token(f, NULL, NULL))) {
if (!strcmp(token, "}")) {
if (in_id && !comma_last)
@@ -402,7 +450,7 @@ static int array_is_hash(FILE *f)
int level = 1;
for (;;) {
- token = next_token(f, NULL);
+ token = next_token(f, NULL, NULL);
if (!token)
goto ret;
@@ -453,7 +501,7 @@ static int parse_array(FILE *f, const char *arr_id, struct data_node **ret)
*ret = data_node_array();
for (;;) {
- if (!(token = next_token(f, NULL)))
+ if (!(token = next_token(f, NULL, NULL)))
return 1;
if (!strcmp(token, "{")) {
@@ -529,14 +577,14 @@ static int parse_get_array_len(FILE *f)
const char *token;
int cnt = 0, depth = 0, prev_comma = 0;
- if (!(token = next_token(f, NULL)))
+ if (!(token = next_token(f, NULL, NULL)))
return 0;
if (strcmp(token, "{"))
return 0;
for (;;) {
- if (!(token = next_token(f, NULL)))
+ if (!(token = next_token(f, NULL, NULL)))
return 0;
if (!strcmp(token, "{"))
@@ -565,7 +613,7 @@ static void look_for_array_size(FILE *f, const char *arr_id, struct data_node **
int prev_buf = 1;
for (;;) {
- if (!(token = next_token2(f, buf[cur_buf], sizeof(buf[cur_buf]), NULL)))
+ if (!(token = next_token2(f, buf[cur_buf], sizeof(buf[cur_buf]), NULL, NULL)))
break;
if (!strcmp(token, "=") && !strcmp(buf[prev_buf], arr_id)) {
@@ -595,13 +643,13 @@ static int parse_array_size(FILE *f, struct data_node **res)
*res = NULL;
- if (!(token = next_token(f, NULL)))
+ if (!(token = next_token(f, NULL, NULL)))
return 1;
if (strcmp(token, "("))
return 1;
- if (!(token = next_token(f, NULL)))
+ if (!(token = next_token(f, NULL, NULL)))
return 1;
arr_id = strdup(token);
@@ -621,7 +669,7 @@ static int parse_array_size(FILE *f, struct data_node **res)
rewind(f);
for (;;) {
- if (!(token = next_token(f, NULL)))
+ if (!(token = next_token(f, NULL, NULL)))
break;
if (token[0] == '#') {
@@ -654,7 +702,8 @@ static int parse_array_size(FILE *f, struct data_node **res)
return 0;
}
-static int parse_test_struct(FILE *f, struct data_node *doc, struct data_node *node)
+static int parse_test_struct(FILE *f, struct data_node *doc,
+ struct data_node *groups, struct data_node *node)
{
char *token;
char *id = NULL;
@@ -662,7 +711,7 @@ static int parse_test_struct(FILE *f, struct data_node *doc, struct data_node *n
struct data_node *ret;
for (;;) {
- if (!(token = next_token(f, doc)))
+ if (!(token = next_token(f, doc, groups)))
return 1;
if (!strcmp(token, "}"))
@@ -842,7 +891,7 @@ static void parse_include_macros(FILE *f, int level)
if (!inc)
return;
- while ((token = next_token(inc, NULL))) {
+ while ((token = next_token(inc, NULL, NULL))) {
if (token[0] == '#') {
hash = 1;
continue;
@@ -907,6 +956,47 @@ static void load_internal_macros(void)
fprintf(stderr, "END PREDEFINED MACROS\n");
}
+/*
+ * Add groups derived from the source file path.
+ *
+ * Groups are the two nearest parent directories (immediate parent
+ * first), skipping 'kernel' as it's too generic:
+ *
+ * testcases/kernel/syscalls/clone/clone01.c -> clone, syscalls
+ * testcases/kernel/kvm/kvm_pagefault01.c -> kvm
+ * testcases/cve/cve-2017-16939.c -> cve
+ */
+static void add_path_groups(struct data_node *groups, const char *fname)
+{
+ char *buf;
+ char *dirs[8];
+ int ndirs = 0;
+ char *p;
+
+ if (strncmp(fname, "testcases/", 10))
+ return;
+
+ buf = strdup(fname + 10);
+ if (!buf)
+ return;
+
+ p = strtok(buf, "/");
+ while (p && ndirs < 8) {
+ dirs[ndirs++] = p;
+ p = strtok(NULL, "/");
+ }
+
+ /* Last element is the filename, skip it */
+ ndirs--;
+
+ if (ndirs >= 1)
+ add_group(groups, dirs[ndirs - 1]);
+ if (ndirs >= 2)
+ add_group(groups, dirs[ndirs - 2]);
+
+ free(buf);
+}
+
static struct data_node *parse_file(const char *fname)
{
int state = 0, found = 0;
@@ -923,15 +1013,18 @@ static struct data_node *parse_file(const char *fname)
struct data_node *res = data_node_hash();
struct data_node *doc = data_node_array();
+ struct data_node *groups = data_node_array();
+
+ add_path_groups(groups, fname);
load_internal_macros();
- while ((token = next_token(f, doc))) {
+ while ((token = next_token(f, doc, groups))) {
if (state < 6 && !strcmp(tokens[state], token)) {
state++;
} else {
if (token[0] == '#') {
- token = next_token(f, doc);
+ token = next_token(f, doc, groups);
if (token) {
if (!strcmp(token, "define"))
parse_macro(f);
@@ -948,7 +1041,7 @@ static struct data_node *parse_file(const char *fname)
continue;
found = 1;
- parse_test_struct(f, doc, res);
+ parse_test_struct(f, doc, groups, res);
}
if (data_node_array_len(doc)) {
@@ -958,6 +1051,11 @@ static struct data_node *parse_file(const char *fname)
data_node_free(doc);
}
+ if (data_node_array_len(groups))
+ data_node_hash_add(res, "groups", groups);
+ else
+ data_node_free(groups);
+
fclose(f);
if (!found) {
@@ -985,7 +1083,7 @@ static void parse_must_files(void)
if (!f)
continue;
- while ((token = next_token(f, NULL))) {
+ while ((token = next_token(f, NULL, NULL))) {
if (!strcmp(token, "define"))
parse_macro(f);
}
@@ -1238,6 +1336,7 @@ int main(int argc, char *argv[])
}
data_node_hash_add(res, "fname", data_node_string(argv[optind]));
+
printf(" \"%s\": ", strip_name(argv[optind]));
data_to_json(res, stdout, 2);
data_node_free(res);
diff --git a/metadata/tests/groups.c b/metadata/tests/groups.c
new file mode 100644
index 0000000000000000000000000000000000000000..40032a7ef60e398c50690995fc68025575d7f684
--- /dev/null
+++ b/metadata/tests/groups.c
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/*\
+ * Test for @groups tag parsing.
+ *
+ * @groups stress regression
+ * @groups smoke
+ */
+
+static struct tst_test test = {
+};
diff --git a/metadata/tests/groups.c.json b/metadata/tests/groups.c.json
new file mode 100644
index 0000000000000000000000000000000000000000..2ca8b5d21d980cdffae4bdaeea20b659a52bad8a
--- /dev/null
+++ b/metadata/tests/groups.c.json
@@ -0,0 +1,12 @@
+ "groups": {
+ "doc": [
+ "Test for @groups tag parsing.",
+ ""
+ ],
+ "groups": [
+ "stress",
+ "regression",
+ "smoke"
+ ],
+ "fname": "groups.c"
+ }
\ No newline at end of file
--
2.51.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [LTP] [PATCH v2 2/2] doc: conf.py: Show groups in test catalog
2026-06-18 14:10 [LTP] [PATCH v2 0/2] Support metadata groups Andrea Cervesato
2026-06-18 14:10 ` [LTP] [PATCH v2 1/2] metadata: add tests grouping support Andrea Cervesato
@ 2026-06-18 14:10 ` Andrea Cervesato
1 sibling, 0 replies; 5+ messages in thread
From: Andrea Cervesato @ 2026-06-18 14:10 UTC (permalink / raw)
To: Linux Test Project
From: Andrea Cervesato <andrea.cervesato@suse.com>
Display the groups field from metadata in the generated test catalog
pages. Groups appear after the source link and before the test
description.
Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
doc/conf.py | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/doc/conf.py b/doc/conf.py
index 591c1534dfa7e54b816e88b9eca1dd7fb91df255..c28db7af1622d28ff79d128c73e3e3c9d8dea112 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -394,6 +394,7 @@ def _generate_setup_table(keys):
'needs_checkpoints',
'forks_child',
'tags',
+ 'groups',
]
my_keys = {k: v for k, v in keys.items() if k not in exclude}
if len(my_keys) == 0:
@@ -482,6 +483,15 @@ def generate_test_catalog(_):
''
])
+ # groups information
+ groups = conf.get('groups', None)
+ if groups:
+ text.extend([
+ '',
+ f"**Groups**: {', '.join(groups)}",
+ ''
+ ])
+
# test description
desc = conf.get('doc', None)
if desc:
--
2.51.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [LTP] metadata: add tests grouping support
2026-06-18 14:10 ` [LTP] [PATCH v2 1/2] metadata: add tests grouping support Andrea Cervesato
@ 2026-06-18 16:40 ` linuxtestproject.agent
0 siblings, 0 replies; 5+ messages in thread
From: linuxtestproject.agent @ 2026-06-18 16:40 UTC (permalink / raw)
To: Andrea Cervesato; +Cc: ltp
Hi Andrea,
On Thu, 18 Jun 2026 16:10:26 +0200, Andrea Cervesato wrote:
> metadata: add tests grouping support
--- [PATCH 1/2] ---
> +#define GROUPS_TAG "groups"
> +static int parse_groups(struct data_node *groups, char *line)
> +{
> + s = (char *)eat_asterisk_space(line);
> + if (strncmp(s, GROUPS_TAG, sizeof(GROUPS_TAG) - 1))
> + return 0;
After eat_asterisk_space() strips the leading " * " from a doc
comment line, the string still begins with '@' (e.g. "@groups stress
regression"). The strncmp therefore compares "@group" against
"groups", which never matches.
Should GROUPS_TAG be "@groups" instead?
Verdict - Needs revision
---
Note:
The agent can sometimes produce false positives although often its
findings are genuine. If you find issues with the review, please
comment this email or ignore the suggestions.
Regards,
LTP AI Reviewer
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-06-18 16:40 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-18 14:10 [LTP] [PATCH v2 0/2] Support metadata groups Andrea Cervesato
2026-06-18 14:10 ` [LTP] [PATCH v2 1/2] metadata: add tests grouping support Andrea Cervesato
2026-06-18 16:40 ` [LTP] " linuxtestproject.agent
2026-06-18 14:10 ` [LTP] [PATCH v2 2/2] doc: conf.py: Show groups in test catalog Andrea Cervesato
-- strict thread matches above, loose matches on Subject: below --
2026-06-12 13:54 [LTP] [PATCH 1/2] metadata: add tests grouping support Andrea Cervesato
2026-06-12 19:10 ` [LTP] " linuxtestproject.agent
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.