[LTP] [PATCH 1/2] lib: add cmd parse handler in needs_cmd

Yang Xu
2021-12-01T07:54:01Z

Testcase ie statx05 needs mkfs.ext4 >= 1.43.0 because of encrypt feature.

As Cyril suggested, add cmd parser handler in needs_cmd.

The difference logic about from before, we don't report not-found error and think it is
cmd version string(need to use tst_version_parser) if tst_get_path fails in tst_test.c.

In tst_version_parser function, use strtok_r to split cmd_token,op_token,version_token.
It only supports six operations '>=' '<=' '>' '<' '==' '!='.

Currently, this tst_version_parser only supports mkfs.ext4 command. If you want to support
more commands, just add your own .parser and .table_get methond in version_parsers structure.

Suggested-by: Cyril Hrubis <chrubis@suse.cz>
Signed-off-by: Yang Xu <xuyang2018.jy@fujitsu.com>
---
doc/c-test-api.txt | 14 +++
include/tst_test.h | 1 +
include/tst_version_parser.h | 15 +++
lib/newlib_tests/.gitignore | 5 +
lib/newlib_tests/test_version_parser01.c | 25 ++++
lib/newlib_tests/test_version_parser02.c | 24 ++++
lib/newlib_tests/test_version_parser03.c | 24 ++++
lib/newlib_tests/test_version_parser04.c | 24 ++++
lib/newlib_tests/test_version_parser05.c | 24 ++++
lib/tst_test.c | 2 +-
lib/tst_version_parser.c | 148 +++++++++++++++++++++++
11 files changed, 305 insertions(+), 1 deletion(-)
create mode 100644 include/tst_version_parser.h
create mode 100644 lib/newlib_tests/test_version_parser01.c
create mode 100644 lib/newlib_tests/test_version_parser02.c
create mode 100644 lib/newlib_tests/test_version_parser03.c
create mode 100644 lib/newlib_tests/test_version_parser04.c
create mode 100644 lib/newlib_tests/test_version_parser05.c
create mode 100644 lib/tst_version_parser.c

diff --git a/doc/c-test-api.txt b/doc/c-test-api.txt
index 64d0630ce..fde6dce0c 100644
--- a/doc/c-test-api.txt
+++ b/doc/c-test-api.txt
@@ -2013,6 +2013,20 @@ terminated array of strings such as:
},
-------------------------------------------------------------------------------

+Also can check required commands version whether is satisfied by using 'needs_cmds',
+
+[source,c]
+-------------------------------------------------------------------------------
+.needs_cmds = (const char *const []) {
+ "mkfs.ext4 >= 1.43.0",
+ NULL
+},
++-------------------------------------------------------------------------------
+
+Currently, we only support mkfs.ext4 command. If you want to support more commands,
+please fill your own .parser and .table_get method in the version_parsers structure
+of lib/tst_version_parser.c.
+
1.36 Assert sys or proc file value
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Using TST_ASSERT_INT/STR(path, val) to assert that integer value or string stored in
diff --git a/include/tst_test.h b/include/tst_test.h
index c06a4729b..fd3d4cfee 100644
--- a/include/tst_test.h
+++ b/include/tst_test.h
@@ -44,6 +44,7 @@
#include "tst_taint.h"
#include "tst_memutils.h"
#include "tst_arch.h"
+#include "tst_version_parser.h"

/*
* Reports testcase result.
diff --git a/include/tst_version_parser.h b/include/tst_version_parser.h
new file mode 100644
index 000000000..145043929
--- /dev/null
+++ b/include/tst_version_parser.h
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2021 Yang Xu <xuyang2018.jy@fujitsu.com>
+ */
+
+#ifndef TST_VERSION_PARSER_H__
+#define TST_VERSION_PARSER_H__
+
+/*
+ * Parse the cmd version requirement in needs_cmds member of tst_test
+ * structure whether is satisfied.
+ */
+void tst_version_parser(const char *cmd);
+
+#endif /* TST_VERSION_PARSER_H__ */
diff --git a/lib/newlib_tests/.gitignore b/lib/newlib_tests/.gitignore
index cf467b5a0..ef8694d08 100644
--- a/lib/newlib_tests/.gitignore
+++ b/lib/newlib_tests/.gitignore
@@ -46,4 +46,9 @@ test_macros06
tst_fuzzy_sync01
tst_fuzzy_sync02
tst_fuzzy_sync03
+test_version_parser01
+test_version_parser02
+test_version_parser03
+test_version_parser04
+test_version_parser05
test_zero_hugepage
diff --git a/lib/newlib_tests/test_version_parser01.c b/lib/newlib_tests/test_version_parser01.c
new file mode 100644
index 000000000..9e1bd3962
--- /dev/null
+++ b/lib/newlib_tests/test_version_parser01.c
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2021 Yang Xu <xuyang2018.jy@fujitsu.com>
+ */
+
+#include <stdio.h>
+#include "tst_test.h"
+
+static void do_test(void)
+{
+ tst_res(TPASS, "Tesing tst_version_parser() functionality OK.");
+}
+
+static struct tst_test test = {
+ .test_all = do_test,
+ .needs_cmds = (const char *[]) {
+ "mkfs.ext4",
+ "mkfs.ext4 >= 1.43.0",
+ "mkfs.ext4 <= 2.0.0",
+ "mkfs.ext4 != 2.0.0",
+ "mkfs.ext4 > 1.43.0",
+ "mkfs.ext4 < 2.0.0",
+ NULL
+ }
+};
diff --git a/lib/newlib_tests/test_version_parser02.c b/lib/newlib_tests/test_version_parser02.c
new file mode 100644
index 000000000..5aedaa28f
--- /dev/null
+++ b/lib/newlib_tests/test_version_parser02.c
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2021 Yang Xu <xuyang2018.jy@fujitsu.com>
+ */
+
+/*
+ * Test Illegal format by using Illegal cmd.
+ */
+
+#include <stdio.h>
+#include "tst_test.h"
+
+static void do_test(void)
+{
+ tst_res(TFAIL, "Tesing tst_version_parser() functionality bad.");
+}
+
+static struct tst_test test = {
+ .test_all = do_test,
+ .needs_cmds = (const char *[]) {
+ "mkfs.ext45 >= 1.43.0",
+ NULL
+ }
+};
diff --git a/lib/newlib_tests/test_version_parser03.c b/lib/newlib_tests/test_version_parser03.c
new file mode 100644
index 000000000..8f96e68d2
--- /dev/null
+++ b/lib/newlib_tests/test_version_parser03.c
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2021 Yang Xu <xuyang2018.jy@fujitsu.com>
+ */
+
+/*
+ * Test Illegal format by using Illegal operation.
+ */
+
+#include <stdio.h>
+#include "tst_test.h"
+
+static void do_test(void)
+{
+ tst_res(TFAIL, "Tesing tst_version_parser() functionality bad.");
+}
+
+static struct tst_test test = {
+ .test_all = do_test,
+ .needs_cmds = (const char *[]) {
+ "mkfs.ext4 ! 1.43.0",
+ NULL
+ }
+};
diff --git a/lib/newlib_tests/test_version_parser04.c b/lib/newlib_tests/test_version_parser04.c
new file mode 100644
index 000000000..461f673df
--- /dev/null
+++ b/lib/newlib_tests/test_version_parser04.c
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2021 Yang Xu <xuyang2018.jy@fujitsu.com>
+ */
+
+/*
+ * Test Illegal format by using Illegal version.
+ */
+
+#include <stdio.h>
+#include "tst_test.h"
+
+static void do_test(void)
+{
+ tst_res(TFAIL, "Tesing tst_version_parser() functionality bad.");
+}
+
+static struct tst_test test = {
+ .test_all = do_test,
+ .needs_cmds = (const char *[]) {
+ "mkfs.ext4 > 1.43",
+ NULL
+ }
+};
diff --git a/lib/newlib_tests/test_version_parser05.c b/lib/newlib_tests/test_version_parser05.c
new file mode 100644
index 000000000..1bfe24f73
--- /dev/null
+++ b/lib/newlib_tests/test_version_parser05.c
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2021 Yang Xu <xuyang2018.jy@fujitsu.com>
+ */
+
+/*
+ * Test non-existed cmd whether still can be detected.
+ */
+
+#include <stdio.h>
+#include "tst_test.h"
+
+static void do_test(void)
+{
+ tst_res(TFAIL, "Tesing tst_version_parser() functionality bad.");
+}
+
+static struct tst_test test = {
+ .test_all = do_test,
+ .needs_cmds = (const char *[]) {
+ "mkfs.ext45",
+ NULL
+ }
+};
diff --git a/lib/tst_test.c b/lib/tst_test.c
index a79275722..a9e95a3d7 100644
--- a/lib/tst_test.c
+++ b/lib/tst_test.c
@@ -992,7 +992,7 @@ static void do_setup(int argc, char *argv[])

for (i = 0; (cmd = tst_test->needs_cmds[i]); ++i)
if (tst_get_path(cmd, path, sizeof(path)))
- tst_brk(TCONF, "Couldn't find '%s' in $PATH", cmd);
+ tst_version_parser(cmd);
}

if (tst_test->needs_drivers) {
diff --git a/lib/tst_version_parser.c b/lib/tst_version_parser.c
new file mode 100644
index 000000000..296e25ea2
--- /dev/null
+++ b/lib/tst_version_parser.c
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2021 Yang Xu <xuyang2018.jy@fujitsu.com>
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define TST_NO_DEFAULT_MAIN
+#include "tst_version_parser.h"
+#include "tst_test.h"
+
+static int mkfs_ext4_version_parser(void)
+{
+ FILE *f;
+ int rc, major, minor, patch;
+
+ f = popen("mkfs.ext4 -V 2>&1", "r");
+ if (!f) {
+ tst_res(TWARN, "Could not run mkfs.ext4 -V 2>&1 cmd");
+ return -1;
+ }
+ rc = fscanf(f, "mke2fs %d.%d.%d", &major, &minor, &patch);
+ pclose(f);
+ if (rc != 3) {
+ tst_res(TWARN, "Unable to parse mkfs.ext4 version");
+ return -1;
+ }
+
+ return major * 10000 + minor * 100 + patch;
+}
+
+static int mkfs_ext4_version_table_get(char *version)
+{
+ char *major, *minor, *patch, *next, *str;
+ char table_version[100];
+
+ strcpy(table_version, version);
+
+ major = strtok_r(table_version, ".", &next);
+ minor = strtok_r(NULL, ".", &next);
+ patch = strtok_r(NULL, ".", &next);
+ str = strtok_r(NULL, ".", &next);
+ if (!major || !minor || !patch || str) {
+ tst_res(TWARN, "Illegal version(%s), should use format like 1.43.0", version);
+ return -1;
+ }
+
+ return atoi(major) * 10000 + atoi(minor) * 100 + atoi(patch);
+}
+
+static struct version_parser {
+ const char *cmd;
+ int (*parser)(void);
+ int (*table_get)(char *version);
+} version_parsers[] = {
+ {.cmd = "mkfs.ext4", .parser = mkfs_ext4_version_parser, .table_get = mkfs_ext4_version_table_get},
+ {},
+};
+
+void tst_version_parser(const char *cmd)
+{
+ struct version_parser *p;
+ char *cmd_token, *op, *version, *next, *str;
+ char path[PATH_MAX];
+ char parser_cmd[100];
+ int ver_parser, ver_get;
+ int op_flag = 0;
+
+ strcpy(parser_cmd, cmd);
+
+ cmd_token = strtok_r(parser_cmd, " ", &next);
+ op = strtok_r(NULL, " ", &next);
+ version = strtok_r(NULL, " ", &next);
+ str = strtok_r(NULL, " ", &next);
+ if (!cmd_token || !op || !version || str)
+ tst_brk(TCONF,
+ "Illegal fomart(%s), should use format like mkfs.ext4 >= 1.43.0", cmd);
+
+ if (tst_get_path(cmd_token, path, sizeof(path)))
+ tst_brk(TCONF, "Couldn't find '%s' in $PATH", cmd_token);
+
+ if (!strcmp(op, ">="))
+ op_flag = 1;
+
+ if (!strcmp(op, ">"))
+ op_flag = 2;
+
+ if (!strcmp(op, "<="))
+ op_flag = 3;
+
+ if (!strcmp(op, "<"))
+ op_flag = 4;
+
+ if (!strcmp(op, "=="))
+ op_flag = 5;
+
+ if (!strcmp(op, "!="))
+ op_flag = 6;
+
+ if (!op_flag)
+ tst_brk(TCONF, "Invalid op(%s)", op);
+
+ for (p = &version_parsers[0]; p; p++) {
+ if (!strcmp(p->cmd, cmd_token))
+ tst_res(TINFO, "Parsing %s version", p->cmd);
+ break;
+ }
+
+ if (!p->cmd)
+ tst_brk(TBROK, "No version parser for %s implemented!", cmd_token);
+
+ ver_parser = p->parser();
+ if (ver_parser < 0)
+ tst_brk(TBROK, "Failed to parse %s version", p->cmd);
+
+ ver_get = p->table_get(version);
+ if (ver_get < 0)
+ tst_brk(TBROK, "Failed to get %s version", p->cmd);
+
+ switch (op_flag) {
+ case 1:
+ if (ver_parser < ver_get)
+ tst_brk(TCONF, "cmd(%s) expected >= %d, but got %d", cmd, ver_get, ver_parser);
+ break;
+ case 2:
+ if (ver_parser <= ver_get)
+ tst_brk(TCONF, "cmd(%s) expected > %d, but got %d", cmd, ver_get, ver_parser);
+ break;
+ case 3:
+ if (ver_parser > ver_get)
+ tst_brk(TCONF, "cmd(%s) expected <= %d, but got %d", cmd, ver_get, ver_parser);
+ break;
+ case 4:
+ if (ver_parser >= ver_get)
+ tst_brk(TCONF, "cmd(%s) expected < %d, but got %d", cmd, ver_get, ver_parser);
+ break;
+ case 5:
+ if (ver_parser != ver_get)
+ tst_brk(TCONF, "cmd(%s) expected == %d, but got %d", cmd, ver_get, ver_parser);
+ break;
+ case 6:
+ if (ver_parser == ver_get)
+ tst_brk(TCONF, "cmd(%s) expected != %d, but got %d", cmd, ver_get, ver_parser);
+ break;
+ }
+}
--
2.23.0