diff mbox series

lib: TST_EXP_FAIL: Add array variants

Message ID 20240103115700.14585-1-chrubis@suse.cz
State Accepted
Headers show
Series lib: TST_EXP_FAIL: Add array variants | expand

Commit Message

Cyril Hrubis Jan. 3, 2024, 11:57 a.m. UTC
For certain cases there is a possibility of a failure with more than one
errno, for instance testcases with invalid fd may return either EINVAL
or EBADFD and in many cases either one is fine, at least that was the
feedback from kernel devs.

This change also adds a tst_errno_in_set() function that is now the
single place to validate errno for all TST_EXP_FAIL*() variants. That is
intentional since this allows us to implement code to relax the
conditions if needed, e.g. we had requests to allow additional errnos
for systems with SELinux where failures may be caused by the SELinux
policies and the errors may differ.

Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
---
 include/tst_test_macros.h        | 65 ++++++++++++++++++++++++++------
 lib/newlib_tests/test_macros02.c | 11 ++++++
 lib/tst_test_macros.c            | 36 ++++++++++++++++++
 3 files changed, 101 insertions(+), 11 deletions(-)
 create mode 100644 lib/tst_test_macros.c

Comments

Petr Vorel Jan. 4, 2024, 12:53 p.m. UTC | #1
Hi Cyril,

> For certain cases there is a possibility of a failure with more than one
> errno, for instance testcases with invalid fd may return either EINVAL
> or EBADFD and in many cases either one is fine, at least that was the
> feedback from kernel devs.

> This change also adds a tst_errno_in_set() function that is now the
> single place to validate errno for all TST_EXP_FAIL*() variants. That is
> intentional since this allows us to implement code to relax the
> conditions if needed, e.g. we had requests to allow additional errnos
> for systems with SELinux where failures may be caused by the SELinux
> policies and the errors may differ.

+1, this should be merged before release.

Reviewed-by: Petr Vorel <pvorel@suse.cz>

Also thanks for starting docs in tst_test_macros.h (I wanted to add more but
haven't done it yet).

> Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
> ---
>  include/tst_test_macros.h        | 65 ++++++++++++++++++++++++++------
>  lib/newlib_tests/test_macros02.c | 11 ++++++
>  lib/tst_test_macros.c            | 36 ++++++++++++++++++
>  3 files changed, 101 insertions(+), 11 deletions(-)
>  create mode 100644 lib/tst_test_macros.c

> diff --git a/include/tst_test_macros.h b/include/tst_test_macros.h
> index bd0c491c1..5687d0904 100644
> --- a/include/tst_test_macros.h
> +++ b/include/tst_test_macros.h
> @@ -186,7 +186,18 @@ extern void *TST_RET_PTR;
>  			TST_MSG_(TPASS, " passed", #SCALL, ##__VA_ARGS__);     \
>  	} while (0)                                                            \

> -#define TST_EXP_FAIL_SILENT_(PASS_COND, SCALL, SSCALL, ERRNO, ...)             \
> +/*
> + * Returns true if err is in the exp_err array.
> + */
> +int tst_errno_in_set(int err, const int *exp_errs, int exp_errs_cnt);
nit: we already use bool in fuzzy sync header and tst_af_alg.h. We could use it
here as well (it's immediately obvious it's true/false, not e.g. count).

...
> diff --git a/lib/tst_test_macros.c b/lib/tst_test_macros.c
> new file mode 100644
> index 000000000..a36abbea3
> --- /dev/null
> +++ b/lib/tst_test_macros.c
> @@ -0,0 +1,36 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) 2020 Cyril Hrubis <chrubis@suse.cz>
nit: maybe 2024?

> + */
> +
> +#include <stdio.h>
> +#define TST_NO_DEFAULT_MAIN
> +#include "tst_test.h"
> +#include "tst_test_macros.h"
> +
> +int tst_errno_in_set(int err, const int *exp_errs, int exp_errs_cnt)
> +{
> +	int i;
> +
> +	for (i = 0; i < exp_errs_cnt; i++) {
> +		if (err == exp_errs[i])
> +			return 1;
> +	}
> +
> +	return 0;
> +}
> +
> +const char *tst_errno_names(char *buf, const int *exp_errs, int exp_errs_cnt)
> +{
> +	int i;
> +	char *cb = buf;
> +
> +	for (i = 0; i < exp_errs_cnt-1; i++)
> +		cb += sprintf(cb, "%s, ", tst_strerrno(exp_errs[i]));
> +
> +	cb += sprintf(cb, "%s", tst_strerrno(exp_errs[i]));
> +
> +	*cb = 0;
very nit: \0 is for me more readable.

Kind regards,
Petr
> +
> +	return buf;
> +}
Petr Vorel Jan. 4, 2024, 10:57 p.m. UTC | #2
Hi Cyril,

I suppose this patchset is a preparation for splice07, right?

https://lore.kernel.org/ltp/20231024093320.wsusd5qtveqt64dt@quack3/

Hopefully we could merge this and tst_fd iterator API before the release.

Kind regards,
Petr
Cyril Hrubis Jan. 15, 2024, 11:05 a.m. UTC | #3
Hi!
> Reviewed-by: Petr Vorel <pvorel@suse.cz>

Merged with the proposed changes.
Cyril Hrubis Jan. 15, 2024, 11:05 a.m. UTC | #4
Hi!
> I suppose this patchset is a preparation for splice07, right?
> 
> https://lore.kernel.org/ltp/20231024093320.wsusd5qtveqt64dt@quack3/
> 
> Hopefully we could merge this and tst_fd iterator API before the release.

Yes, I'm working on that now.
diff mbox series

Patch

diff --git a/include/tst_test_macros.h b/include/tst_test_macros.h
index bd0c491c1..5687d0904 100644
--- a/include/tst_test_macros.h
+++ b/include/tst_test_macros.h
@@ -186,7 +186,18 @@  extern void *TST_RET_PTR;
 			TST_MSG_(TPASS, " passed", #SCALL, ##__VA_ARGS__);     \
 	} while (0)                                                            \
 
-#define TST_EXP_FAIL_SILENT_(PASS_COND, SCALL, SSCALL, ERRNO, ...)             \
+/*
+ * Returns true if err is in the exp_err array.
+ */
+int tst_errno_in_set(int err, const int *exp_errs, int exp_errs_cnt);
+
+/*
+ * Fills in the buf with the errno names in the exp_err set. The buf must be at
+ * least 20 * exp_errs_cnt bytes long.
+ */
+const char *tst_errno_names(char *buf, const int *exp_errs, int exp_errs_cnt);
+
+#define TST_EXP_FAIL_SILENT_(PASS_COND, SCALL, SSCALL, ERRNOS, ERRNOS_CNT, ...)\
 	do {                                                                   \
 		TEST(SCALL);                                                   \
 		                                                               \
@@ -203,36 +214,68 @@  extern void *TST_RET_PTR;
 			break;                                                 \
 		}                                                              \
 		                                                               \
-		if (TST_ERR == (ERRNO)) {                                      \
+		if (tst_errno_in_set(TST_ERR, ERRNOS, ERRNOS_CNT)) {           \
 			TST_PASS = 1;                                          \
 		} else {                                                       \
+			char tst_str_buf__[ERRNOS_CNT * 20];                   \
 			TST_MSGP_(TFAIL | TTERRNO, " expected %s",             \
-				  tst_strerrno(ERRNO),                         \
+				  tst_errno_names(tst_str_buf__,               \
+						  ERRNOS, ERRNOS_CNT),         \
 				  SSCALL, ##__VA_ARGS__);                      \
 		}                                                              \
 	} while (0)
 
-#define TST_EXP_FAIL(SCALL, ERRNO, ...)                                        \
+#define TST_EXP_FAIL_ARR_(SCALL, EXP_ERRS, EXP_ERRS_CNT, ...)                  \
 	do {                                                                   \
 		TST_EXP_FAIL_SILENT_(TST_RET == 0, SCALL, #SCALL,              \
-			ERRNO, ##__VA_ARGS__);                                 \
+			EXP_ERRS, EXP_ERRS_CNT, ##__VA_ARGS__);                \
 		if (TST_PASS)                                                  \
 			TST_MSG_(TPASS | TTERRNO, " ", #SCALL, ##__VA_ARGS__); \
 	} while (0)
 
-#define TST_EXP_FAIL2(SCALL, ERRNO, ...)                                       \
+#define TST_EXP_FAIL(SCALL, EXP_ERR, ...)                                      \
+	do {                                                                   \
+		int tst_exp_err__ = EXP_ERR;                                   \
+		TST_EXP_FAIL_ARR_(SCALL, &tst_exp_err__, 1,                    \
+                                  ##__VA_ARGS__);                              \
+	} while (0)
+
+#define TST_EXP_FAIL_ARR(SCALL, EXP_ERRS, ...)                                 \
+		TST_EXP_FAIL_ARR_(SCALL, EXP_ERRS, ARRAY_SIZE(EXP_ERRS),       \
+                                  ##__VA_ARGS__);                              \
+
+#define TST_EXP_FAIL2_ARR_(SCALL, EXP_ERRS, EXP_ERRS_CNT, ...)                 \
 	do {                                                                   \
 		TST_EXP_FAIL_SILENT_(TST_RET >= 0, SCALL, #SCALL,              \
-			ERRNO, ##__VA_ARGS__);                                 \
+			EXP_ERRS, EXP_ERRS_CNT, ##__VA_ARGS__);                \
 		if (TST_PASS)                                                  \
 			TST_MSG_(TPASS | TTERRNO, " ", #SCALL, ##__VA_ARGS__); \
 	} while (0)
 
-#define TST_EXP_FAIL_SILENT(SCALL, ERRNO, ...) \
-	TST_EXP_FAIL_SILENT_(TST_RET == 0, SCALL, #SCALL, ERRNO, ##__VA_ARGS__)
+#define TST_EXP_FAIL2_ARR(SCALL, EXP_ERRS, ...)                                \
+		TST_EXP_FAIL2_ARR_(SCALL, EXP_ERRS, ARRAY_SIZE(EXP_ERRS),      \
+                                  ##__VA_ARGS__);                              \
 
-#define TST_EXP_FAIL2_SILENT(SCALL, ERRNO, ...) \
-	TST_EXP_FAIL_SILENT_(TST_RET >= 0, SCALL, #SCALL, ERRNO, ##__VA_ARGS__)
+#define TST_EXP_FAIL2(SCALL, EXP_ERR, ...)                                     \
+	do {                                                                   \
+		int tst_exp_err__ = EXP_ERR;                                   \
+		TST_EXP_FAIL2_ARR_(SCALL, &tst_exp_err__, 1,                   \
+                                  ##__VA_ARGS__);                              \
+	} while (0)
+
+#define TST_EXP_FAIL_SILENT(SCALL, EXP_ERR, ...)                               \
+	do {                                                                   \
+		int tst_exp_err__ = EXP_ERR;                                   \
+		TST_EXP_FAIL_SILENT_(TST_RET == 0, SCALL, #SCALL,              \
+			&tst_exp_err__, 1, ##__VA_ARGS__);                     \
+	} while (0)
+
+#define TST_EXP_FAIL2_SILENT(SCALL, EXP_ERR, ...)                              \
+	do {                                                                   \
+		int tst_exp_err__ = EXP_ERR;                                   \
+		TST_EXP_FAIL_SILENT_(TST_RET >= 0, SCALL, #SCALL,              \
+			&tst_exp_err__, 1, ##__VA_ARGS__);                     \
+	} while (0)
 
 #define TST_EXP_EXPR(EXPR, FMT, ...)						\
 	tst_res_(__FILE__, __LINE__, (EXPR) ? TPASS : TFAIL, "Expect: " FMT, ##__VA_ARGS__);
diff --git a/lib/newlib_tests/test_macros02.c b/lib/newlib_tests/test_macros02.c
index 647f73682..6c1ca7a8a 100644
--- a/lib/newlib_tests/test_macros02.c
+++ b/lib/newlib_tests/test_macros02.c
@@ -27,6 +27,9 @@  static int inval_ret_fn(void)
 
 static void do_test(void)
 {
+	const int exp_errs_pass[] = {ENOTTY, EINVAL};
+	const int exp_errs_fail[] = {ENOTTY, EISDIR};
+
 	tst_res(TINFO, "Testing TST_EXP_FAIL macro");
 	TST_EXP_FAIL(fail_fn(), EINVAL, "fail_fn()");
 	tst_res(TINFO, "TST_PASS = %i", TST_PASS);
@@ -36,6 +39,10 @@  static void do_test(void)
 	tst_res(TINFO, "TST_PASS = %i", TST_PASS);
 	TST_EXP_FAIL(inval_ret_fn(), ENOTTY, "inval_ret_fn()");
 	tst_res(TINFO, "TST_PASS = %i", TST_PASS);
+	TST_EXP_FAIL_ARR(fail_fn(), exp_errs_pass, "fail_fn()");
+	tst_res(TINFO, "TST_PASS = %i", TST_PASS);
+	TST_EXP_FAIL_ARR(fail_fn(), exp_errs_fail, "fail_fn()");
+	tst_res(TINFO, "TST_PASS = %i", TST_PASS);
 
 	tst_res(TINFO, "Testing TST_EXP_FAIL2 macro");
 	TST_EXP_FAIL2(fail_fn(), EINVAL, "fail_fn()");
@@ -46,6 +53,10 @@  static void do_test(void)
 	tst_res(TINFO, "TST_PASS = %i", TST_PASS);
 	TST_EXP_FAIL2(inval_ret_fn(), ENOTTY, "inval_ret_fn()");
 	tst_res(TINFO, "TST_PASS = %i", TST_PASS);
+	TST_EXP_FAIL2_ARR(fail_fn(), exp_errs_pass, "fail_fn()");
+	tst_res(TINFO, "TST_PASS = %i", TST_PASS);
+	TST_EXP_FAIL2_ARR(fail_fn(), exp_errs_fail, "fail_fn()");
+	tst_res(TINFO, "TST_PASS = %i", TST_PASS);
 }
 
 static struct tst_test test = {
diff --git a/lib/tst_test_macros.c b/lib/tst_test_macros.c
new file mode 100644
index 000000000..a36abbea3
--- /dev/null
+++ b/lib/tst_test_macros.c
@@ -0,0 +1,36 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#include <stdio.h>
+#define TST_NO_DEFAULT_MAIN
+#include "tst_test.h"
+#include "tst_test_macros.h"
+
+int tst_errno_in_set(int err, const int *exp_errs, int exp_errs_cnt)
+{
+	int i;
+
+	for (i = 0; i < exp_errs_cnt; i++) {
+		if (err == exp_errs[i])
+			return 1;
+	}
+
+	return 0;
+}
+
+const char *tst_errno_names(char *buf, const int *exp_errs, int exp_errs_cnt)
+{
+	int i;
+	char *cb = buf;
+
+	for (i = 0; i < exp_errs_cnt-1; i++)
+		cb += sprintf(cb, "%s, ", tst_strerrno(exp_errs[i]));
+
+	cb += sprintf(cb, "%s", tst_strerrno(exp_errs[i]));
+
+	*cb = 0;
+
+	return buf;
+}