Commit 64f01e93 authored by Eduard Zingerman's avatar Eduard Zingerman Committed by Andrii Nakryiko
Browse files

selftests/bpf: extract test_loader->expect_msgs as a data structure



Non-functional change: use a separate data structure to represented
expected messages in test_loader.
This would allow to use the same functionality for expected set of
disassembled instructions in the follow-up commit.

Acked-by: default avatarAndrii Nakryiko <andrii@kernel.org>
Signed-off-by: default avatarEduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20240722233844.1406874-8-eddyz87@gmail.com


Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
parent 4ef5d6af
Loading
Loading
Loading
Loading
+41 −40
Original line number Diff line number Diff line
@@ -55,11 +55,15 @@ struct expect_msg {
	regex_t regex;
};

struct expected_msgs {
	struct expect_msg *patterns;
	size_t cnt;
};

struct test_subspec {
	char *name;
	bool expect_failure;
	struct expect_msg *expect_msgs;
	size_t expect_msg_cnt;
	struct expected_msgs expect_msgs;
	int retval;
	bool execute;
};
@@ -96,44 +100,45 @@ void test_loader_fini(struct test_loader *tester)
	free(tester->log_buf);
}

static void free_test_spec(struct test_spec *spec)
static void free_msgs(struct expected_msgs *msgs)
{
	int i;

	for (i = 0; i < msgs->cnt; i++)
		if (msgs->patterns[i].regex_str)
			regfree(&msgs->patterns[i].regex);
	free(msgs->patterns);
	msgs->patterns = NULL;
	msgs->cnt = 0;
}

static void free_test_spec(struct test_spec *spec)
{
	/* Deallocate expect_msgs arrays. */
	for (i = 0; i < spec->priv.expect_msg_cnt; i++)
		if (spec->priv.expect_msgs[i].regex_str)
			regfree(&spec->priv.expect_msgs[i].regex);
	for (i = 0; i < spec->unpriv.expect_msg_cnt; i++)
		if (spec->unpriv.expect_msgs[i].regex_str)
			regfree(&spec->unpriv.expect_msgs[i].regex);
	free_msgs(&spec->priv.expect_msgs);
	free_msgs(&spec->unpriv.expect_msgs);

	free(spec->priv.name);
	free(spec->unpriv.name);
	free(spec->priv.expect_msgs);
	free(spec->unpriv.expect_msgs);

	spec->priv.name = NULL;
	spec->unpriv.name = NULL;
	spec->priv.expect_msgs = NULL;
	spec->unpriv.expect_msgs = NULL;
}

static int push_msg(const char *substr, const char *regex_str, struct test_subspec *subspec)
static int push_msg(const char *substr, const char *regex_str, struct expected_msgs *msgs)
{
	void *tmp;
	int regcomp_res;
	char error_msg[100];
	struct expect_msg *msg;

	tmp = realloc(subspec->expect_msgs,
		      (1 + subspec->expect_msg_cnt) * sizeof(struct expect_msg));
	tmp = realloc(msgs->patterns,
		      (1 + msgs->cnt) * sizeof(struct expect_msg));
	if (!tmp) {
		ASSERT_FAIL("failed to realloc memory for messages\n");
		return -ENOMEM;
	}
	subspec->expect_msgs = tmp;
	msg = &subspec->expect_msgs[subspec->expect_msg_cnt];
	msgs->patterns = tmp;
	msg = &msgs->patterns[msgs->cnt];

	if (substr) {
		msg->substr = substr;
@@ -150,7 +155,7 @@ static int push_msg(const char *substr, const char *regex_str, struct test_subsp
		}
	}

	subspec->expect_msg_cnt += 1;
	msgs->cnt += 1;
	return 0;
}

@@ -272,25 +277,25 @@ static int parse_test_spec(struct test_loader *tester,
			spec->mode_mask |= UNPRIV;
		} else if (str_has_pfx(s, TEST_TAG_EXPECT_MSG_PFX)) {
			msg = s + sizeof(TEST_TAG_EXPECT_MSG_PFX) - 1;
			err = push_msg(msg, NULL, &spec->priv);
			err = push_msg(msg, NULL, &spec->priv.expect_msgs);
			if (err)
				goto cleanup;
			spec->mode_mask |= PRIV;
		} else if (str_has_pfx(s, TEST_TAG_EXPECT_MSG_PFX_UNPRIV)) {
			msg = s + sizeof(TEST_TAG_EXPECT_MSG_PFX_UNPRIV) - 1;
			err = push_msg(msg, NULL, &spec->unpriv);
			err = push_msg(msg, NULL, &spec->unpriv.expect_msgs);
			if (err)
				goto cleanup;
			spec->mode_mask |= UNPRIV;
		} else if (str_has_pfx(s, TEST_TAG_EXPECT_REGEX_PFX)) {
			msg = s + sizeof(TEST_TAG_EXPECT_REGEX_PFX) - 1;
			err = push_msg(NULL, msg, &spec->priv);
			err = push_msg(NULL, msg, &spec->priv.expect_msgs);
			if (err)
				goto cleanup;
			spec->mode_mask |= PRIV;
		} else if (str_has_pfx(s, TEST_TAG_EXPECT_REGEX_PFX_UNPRIV)) {
			msg = s + sizeof(TEST_TAG_EXPECT_REGEX_PFX_UNPRIV) - 1;
			err = push_msg(NULL, msg, &spec->unpriv);
			err = push_msg(NULL, msg, &spec->unpriv.expect_msgs);
			if (err)
				goto cleanup;
			spec->mode_mask |= UNPRIV;
@@ -387,11 +392,12 @@ static int parse_test_spec(struct test_loader *tester,
			spec->unpriv.execute = spec->priv.execute;
		}

		if (!spec->unpriv.expect_msgs) {
			for (i = 0; i < spec->priv.expect_msg_cnt; i++) {
				struct expect_msg *msg = &spec->priv.expect_msgs[i];
		if (spec->unpriv.expect_msgs.cnt == 0) {
			for (i = 0; i < spec->priv.expect_msgs.cnt; i++) {
				struct expect_msg *msg = &spec->priv.expect_msgs.patterns[i];

				err = push_msg(msg->substr, msg->regex_str, &spec->unpriv);
				err = push_msg(msg->substr, msg->regex_str,
					       &spec->unpriv.expect_msgs);
				if (err)
					goto cleanup;
			}
@@ -443,18 +449,14 @@ static void emit_verifier_log(const char *log_buf, bool force)
	fprintf(stdout, "VERIFIER LOG:\n=============\n%s=============\n", log_buf);
}

static void validate_case(struct test_loader *tester,
			  struct test_subspec *subspec,
			  struct bpf_object *obj,
			  struct bpf_program *prog,
			  int load_err)
static void validate_msgs(char *log_buf, struct expected_msgs *msgs)
{
	regmatch_t reg_match[1];
	const char *log = tester->log_buf;
	const char *log = log_buf;
	int i, j, err;

	for (i = 0; i < subspec->expect_msg_cnt; i++) {
		struct expect_msg *msg = &subspec->expect_msgs[i];
	for (i = 0; i < msgs->cnt; i++) {
		struct expect_msg *msg = &msgs->patterns[i];
		const char *match = NULL;

		if (msg->substr) {
@@ -471,9 +473,9 @@ static void validate_case(struct test_loader *tester,

		if (!ASSERT_OK_PTR(match, "expect_msg")) {
			if (env.verbosity == VERBOSE_NONE)
				emit_verifier_log(tester->log_buf, true /*force*/);
				emit_verifier_log(log_buf, true /*force*/);
			for (j = 0; j <= i; j++) {
				msg = &subspec->expect_msgs[j];
				msg = &msgs->patterns[j];
				fprintf(stderr, "%s %s: '%s'\n",
					j < i ? "MATCHED " : "EXPECTED",
					msg->substr ? "SUBSTR" : " REGEX",
@@ -692,9 +694,8 @@ void run_subtest(struct test_loader *tester,
			goto tobj_cleanup;
		}
	}

	emit_verifier_log(tester->log_buf, false /*force*/);
	validate_case(tester, subspec, tobj, tprog, err);
	validate_msgs(tester->log_buf, &subspec->expect_msgs);

	if (should_do_test_run(spec, subspec)) {
		/* For some reason test_verifier executes programs