diff mbox series

[v2,3/3] libtracefs: Add unit tests for user_events

Message ID 20220222232316.14640-4-beaub@linux.microsoft.com (mailing list archive)
State New, archived
Headers show
Series libtracefs: Add APIs for user_events to libtracefs | expand

Commit Message

Beau Belgrave Feb. 22, 2022, 11:23 p.m. UTC
Adds unit tests for user_events when available. Ensures APIs are working
correctly and appropriate errors are being returned.

Signed-off-by: Beau Belgrave <beaub@linux.microsoft.com>
---
 utest/tracefs-utest.c | 233 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 233 insertions(+)

Comments

Steven Rostedt Feb. 23, 2022, 3:17 p.m. UTC | #1
On Tue, 22 Feb 2022 15:23:16 -0800
Beau Belgrave <beaub@linux.microsoft.com> wrote:

> Adds unit tests for user_events when available. Ensures APIs are working
> correctly and appropriate errors are being returned.
> 
> Signed-off-by: Beau Belgrave <beaub@linux.microsoft.com>
> ---
>  utest/tracefs-utest.c | 233 ++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 233 insertions(+)
> 

OK, so I couldn't get the selftest working because I didn't have
user_events.h. I then worked to get that, but the selftest still failed
with:

After thinking about this a bit, I've decided that I'll release 1.3 without
this patch series.

The reason being, I want 1.3 to get into distros ASAP. As adding this patch
series will put a dependency on user_events.h (yes it builds without it,
but distros want everything that it can build applied), then that puts a
dependency on 1.3 to having user_events.h available, which may be a while
as it has to get into 5.18, and then slowly move to the distro kernels.

If distros did build it without user_events.h and then later on with
user_evnets.h then we have two versions of 1.3 where one supports
user_events and one does not. And you can not use versioning to determine
if your application will link to the library or not.

With all this in mind, I've decided to hold off this to libtracefs 1.4, and
when user_events is solidly in the kernel.

But I'm very excited to have this work in both the kernel and libtracefs. I
just want it properly done though.

Thanks for all your work and I'll keep these patches in my queue for 1.4.

Cheers,

-- Steve
Beau Belgrave Feb. 23, 2022, 5:25 p.m. UTC | #2
On Wed, Feb 23, 2022 at 10:17:15AM -0500, Steven Rostedt wrote:
> On Tue, 22 Feb 2022 15:23:16 -0800
> Beau Belgrave <beaub@linux.microsoft.com> wrote:
> 
> > Adds unit tests for user_events when available. Ensures APIs are working
> > correctly and appropriate errors are being returned.
> > 
> > Signed-off-by: Beau Belgrave <beaub@linux.microsoft.com>
> > ---
> >  utest/tracefs-utest.c | 233 ++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 233 insertions(+)
> > 
> 
> OK, so I couldn't get the selftest working because I didn't have
> user_events.h. I then worked to get that, but the selftest still failed
> with:
> 

The suspense is killing me, what did it fail with? :) (Guessing you saw
the fprintf message when I simulate a failure).

> After thinking about this a bit, I've decided that I'll release 1.3 without
> this patch series.
> 

No worries.

> The reason being, I want 1.3 to get into distros ASAP. As adding this patch
> series will put a dependency on user_events.h (yes it builds without it,
> but distros want everything that it can build applied), then that puts a
> dependency on 1.3 to having user_events.h available, which may be a while
> as it has to get into 5.18, and then slowly move to the distro kernels.
> 

Understood.

> If distros did build it without user_events.h and then later on with
> user_evnets.h then we have two versions of 1.3 where one supports
> user_events and one does not. And you can not use versioning to determine
> if your application will link to the library or not.
> 
> With all this in mind, I've decided to hold off this to libtracefs 1.4, and
> when user_events is solidly in the kernel.
> 
> But I'm very excited to have this work in both the kernel and libtracefs. I
> just want it properly done though.
> 

Yeah, do you want me to send out a v3 with some of the fixes? Or have
you put this into a branch somewhere already (I saw your other patch on
top of this one). I fixed some style nits that were bugging me, as they
didn't align to the kernel style.

Thanks,
-Beau
diff mbox series

Patch

diff --git a/utest/tracefs-utest.c b/utest/tracefs-utest.c
index e8d5c69..ed38d9c 100644
--- a/utest/tracefs-utest.c
+++ b/utest/tracefs-utest.c
@@ -11,6 +11,7 @@ 
 #include <time.h>
 #include <dirent.h>
 #include <ftw.h>
+#include <linux/types.h>
 
 #include <CUnit/CUnit.h>
 #include <CUnit/Basic.h>
@@ -871,6 +872,235 @@  static void test_eprobes(void)
 	test_eprobes_instance(test_instance);
 }
 
+#ifdef USEREVENTS
+struct user_test_context {
+	int seen;
+	int failed;
+};
+static int user_callback(struct tep_event *event, struct tep_record *record,
+			  int cpu, void *context)
+{
+	struct tep_format_field *field;
+	struct user_test_context *user_context;
+	__u32 *rel, size, offset;
+
+	user_context = (struct user_test_context *)context;
+	user_context->seen++;
+
+	field = tep_find_field(event, "u8");
+	if (!field || *(__u8 *)(record->data + field->offset) != 1)
+	{
+		user_context->failed = 1;
+		return -1;
+	}
+
+	field = tep_find_field(event, "s8");
+	if (!field || *(__s8 *)(record->data + field->offset) != 2)
+	{
+		user_context->failed = 2;
+		return -1;
+	}
+
+	field = tep_find_field(event, "u16");
+	if (!field || *(__u16 *)(record->data + field->offset) != 3)
+	{
+		user_context->failed = 3;
+		return -1;
+	}
+
+	field = tep_find_field(event, "s16");
+	if (!field || *(__s16 *)(record->data + field->offset) != 4)
+	{
+		user_context->failed = 4;
+		return -1;
+	}
+
+	field = tep_find_field(event, "u32");
+	if (!field || *(__u32 *)(record->data + field->offset) != 5)
+	{
+		user_context->failed = 5;
+		return -1;
+	}
+
+	field = tep_find_field(event, "s32");
+	if (!field || *(__s32 *)(record->data + field->offset) != 6)
+	{
+		user_context->failed = 6;
+		return -1;
+	}
+
+	field = tep_find_field(event, "u64");
+	if (!field || *(__u64 *)(record->data + field->offset) != 7)
+	{
+		user_context->failed = 7;
+		return -1;
+	}
+
+	field = tep_find_field(event, "s64");
+	if (!field || *(__s64 *)(record->data + field->offset) != 8)
+	{
+		user_context->failed = 8;
+		return -1;
+	}
+
+	field = tep_find_field(event, "string");
+	if (!field || memcmp(record->data + field->offset, "12345678", 8))
+	{
+		user_context->failed = 9;
+		return -1;
+	}
+
+	field = tep_find_field(event, "struct");
+	if (!field || *(__u64 *)(record->data + field->offset) != 9)
+	{
+		user_context->failed = 10;
+		return -1;
+	}
+
+	field = tep_find_field(event, "varray");
+	if (!field) {
+		user_context->failed = 11;
+		return -1;
+	}
+
+	rel = (__u32 *)(record->data + field->offset);
+	offset = *rel & 0xffff;
+	size = *rel >> 16;
+	rel++;
+
+	if (memcmp((void *)(rel) + offset, "Array", size)) {
+		user_context->failed = 12;
+		return -1;
+	}
+
+	field = tep_find_field(event, "vstring");
+	if (!field) {
+		user_context->failed = 13;
+		return -1;
+	}
+
+	rel = (__u32 *)(record->data + field->offset);
+	offset = *rel & 0xffff;
+	size = *rel >> 16;
+	rel++;
+
+	if (memcmp((void *)(rel) + offset, "Variable", size)) {
+		user_context->failed = 14;
+		return -1;
+	}
+
+	return 0;
+}
+
+static void test_userevents_instance(struct tracefs_instance *instance)
+{
+	struct tracefs_user_event_group *group;
+	struct tracefs_user_event *event;
+	struct tep_handle *user_tep;
+	enum tracefs_uevent_flags flags = TRACEFS_UEVENT_FLAG_NONE;
+	const char *systems[] = { "user_events", NULL };
+	const char *name = "libtracefs_utest";
+	const char *system = "user_events";
+	const char *test_string = "12345678";
+	const char *test_array = "Array";
+	const char *test_vstring = "Variable";
+	__u8 a = 1;
+	__s8 b = 2;
+	__u16 c = 3;
+	__s16 d = 4;
+	__u32 e = 5;
+	__s32 f = 6;
+	__u64 g = 7;
+	__s64 h = 8;
+	__u64 i = 9;
+	struct tracefs_uevent_item all_items[] = {
+		{ TRACEFS_UEVENT_u8, .name = "u8" },
+		{ TRACEFS_UEVENT_s8, .name = "s8" },
+		{ TRACEFS_UEVENT_u16, .name = "u16" },
+		{ TRACEFS_UEVENT_s16, .name = "s16" },
+		{ TRACEFS_UEVENT_u32, .name = "u32" },
+		{ TRACEFS_UEVENT_s32, .name = "s32" },
+		{ TRACEFS_UEVENT_u64, .name = "u64" },
+		{ TRACEFS_UEVENT_s64, .name = "s64" },
+		{ TRACEFS_UEVENT_string, .name = "string", .len = 8 },
+		{ TRACEFS_UEVENT_struct, .name = "test struct", .len = 8 },
+		{ TRACEFS_UEVENT_varray, .name = "varray" },
+		{ TRACEFS_UEVENT_vstring, .name = "vstring" },
+		{ TRACEFS_UEVENT_END },
+	};
+	struct tracefs_uevent_item write_items[] = {
+		{ TRACEFS_UEVENT_u8, .data = &a, .len = sizeof(a) },
+		{ TRACEFS_UEVENT_s8, .data = &b, .len = sizeof(b) },
+		{ TRACEFS_UEVENT_u16, .data = &c, .len = sizeof(c) },
+		{ TRACEFS_UEVENT_s16, .data = &d, .len = sizeof(d) },
+		{ TRACEFS_UEVENT_u32, .data = &e, .len = sizeof(e) },
+		{ TRACEFS_UEVENT_s32, .data = &f, .len = sizeof(f) },
+		{ TRACEFS_UEVENT_u64, .data = &g, .len = sizeof(g) },
+		{ TRACEFS_UEVENT_s64, .data = &h, .len = sizeof(h) },
+		{ TRACEFS_UEVENT_string, .data = test_string,
+					 .len = strlen(test_string) },
+		{ TRACEFS_UEVENT_struct, .data = &i, .len = sizeof(i) },
+		{ TRACEFS_UEVENT_varray, .data = test_array,
+					 .len = strlen(test_array) },
+		{ TRACEFS_UEVENT_vstring, .data = test_vstring,
+					  .len = strlen(test_vstring)+1 },
+		{ TRACEFS_UEVENT_END },
+	};
+	struct user_test_context context;
+	int ret;
+
+	/* Delete if it already exists */
+	tracefs_user_event_delete(name);
+
+	group = tracefs_user_event_group_open();
+	CU_TEST(group != NULL);
+
+	event = tracefs_user_event_register(group, name, flags, all_items);
+	CU_TEST(event != NULL);
+
+	/* Test enable and status */
+	CU_TEST(!tracefs_user_event_enabled(event));
+	CU_TEST(tracefs_event_enable(instance, system, name) == 0);
+	CU_TEST(tracefs_user_event_enabled(event));
+
+	/* Correct record should work */
+	CU_TEST(tracefs_user_event_record(event, write_items) > 0);
+
+	/* Ensure record output was correct */
+	user_tep = tracefs_local_events_system(NULL, systems);
+	CU_TEST(user_tep != NULL);
+
+	memset(&context, 0, sizeof(context));
+	ret = tracefs_iterate_raw_events(user_tep, instance, NULL, 0,
+					 user_callback, &context);
+	tep_free(user_tep);
+
+	CU_TEST(ret == 0);
+	CU_TEST(context.seen == 1);
+	CU_TEST(context.failed == 0);
+
+	/* Simulate bad length */
+	write_items[0].len = 0;
+	CU_TEST(tracefs_user_event_record(event, write_items) == -1);
+
+	/* Simulate bad pointer */
+	write_items[0].len = sizeof(a);
+	write_items[0].data = NULL;
+	CU_TEST(tracefs_user_event_record(event, write_items) == -1);
+
+	tracefs_user_event_group_close(group);
+
+	/* Disable and deletion must work */
+	CU_TEST(tracefs_event_disable(instance, system, name) == 0);
+	CU_TEST(tracefs_user_event_delete(name) == 0);
+}
+
+static void test_userevents(void)
+{
+	test_userevents_instance(test_instance);
+}
+#endif
+
 static void test_instance_file(void)
 {
 	struct tracefs_instance *instance = NULL;
@@ -1706,4 +1936,7 @@  void test_tracefs_lib(void)
 	CU_add_test(suite, "kprobes", test_kprobes);
 	CU_add_test(suite, "syntetic events", test_synthetic);
 	CU_add_test(suite, "eprobes", test_eprobes);
+#ifdef USEREVENTS
+	CU_add_test(suite, "user events", test_userevents);
+#endif
 }