Skip to contentSkip to conversation

Testbeds for libudev/gudev clients

PATCH New Martin Pitt 1 participant 1 message Jul 10, 2012 Kbuild

lore
Share & tools
lore
#0 lore raw

PATCH v2 1/1 Testbeds for libudev/gudev clients

Hello again,

Martin Pitt [2012-07-06 7:01 +0200]:

Quoted 8 lines

I have a patch attached to generalize this to use $UDEV_TEST_PREFIX, replacing the current compile-time TEST_PREFIX macro. This will also allow us in the future to create mock dev and run/rules.d files without having to change the environment variable and temporary directory structure again. Once that (or a variant of it) is in, I'll adapt upower's test suite to also set UDEV_TEST_PREFIX so that it works with both old and new libudev versions.

As the original patch that changed libudev to respect $UDEV_TEST_PREFIX was not very palatable, I now changed the approach to use an external LD_PRELOAD wrapper, as discussed with Lucas. This is the "no privileges" and "do not do any permanent changes to the system" variant of Kay's namespacing proposal, and does not touch the existing code at all. I based libudev-testbed.so on kmod's path.c, simplified it a bit, added some missing functions, and integrated it into the build system together with a simple "libudev-testbed" wrapper script that you need to run test suites under.

I actually like this approach, as it allows us to extend the functionality later on. E. g. this can easily intercept access to /dev/ and sysctls as well.

Quoted 4 lines
   With that patch you can now e. g. call

     UDEV_TEST_PREFIX=test ./udevadm info --export-db
     UDEV_TEST_PREFIX=test ./udevadm info --query=all --path=/devices/virtual/block/md0

This now becomes

  LD_LIBRARY_PATH=.libs UDEV_TEST_PREFIX=test src/test/libudev-testbed  ./udevadm info --export-db

The LD_LIBRARY_PATH is just for the build tree; when using the installed version (e. g. upower's test suite), you would use

  UDEV_TEST_PREFIX=/path/to/testbed libudev-testbed /udevadm info --export-db

I also adjusted the GUdevTestbed patch a bit for the new approach.

TODOs that I am aware of which need to be fixed before committing:

- libudev-testbed needs a manpage
- GUdevTestbed needs to remove its temporary directory in the destructor
- Write some documentation how to use this stuff (in libudev-testbed's manpage, and some general "how to write tests for hardware handling" wiki page on fd.o)

I'll do these once we have a general agreement about the approach in these patches.

Thanks,

Martin

Signature · 2 lines
Martin Pitt                        | http://www.piware.de
Ubuntu Developer (www.ubuntu.com)  | Debian Developer  (www.debian.org)

From 695119a0a324de98d340ca956e92c60fba949048 Mon Sep 17 00:00:00 2001
From: Martin Pitt <[email protected]>
Date: Tue, 10 Jul 2012 08:48:34 +0200
Subject: [PATCH 1/2] Add libudev test bed wrapper

The removal of $SYSFS_PATH and configurable paths made it impossible for test suites to set up a local sysfs tree and point libudev to that. Restore and generalize the functionality with checking the $UDEV_TEST_PREFIX environment variable, so that test suites can continue to run without root privileges and the danger of breaking the system.

Add a small LD_PRELOAD library (based on path.c from kmod) to wrap the libc functions that libudev needs for prefixing the paths with $UDEV_TEST_PREFIX. Cover sysfs for now (which mostly needs open(), readlink(), and stat()), but this approach is extensible for intercepting sysctls, device node access, and similar things in the future as well.

Also add a small shell wrapper "libudev-testbed" which runs the argument under the appropriate LD_PRELOAD. This is more robust for third party test suites and also allows us to change the test bed implementation in the future. Run all tests under this wrapper; it does not change behaviour if $UDEV_TEST_PREFIX is not set, and will make future selftests of libudev/gudev using the new test bed just work.

---
 Makefile.am                |   27 ++++++
 src/test/libudev-testbed   |    5 ++
 src/test/libudev-testbed.c |  214 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 246 insertions(+)
 create mode 100755 src/test/libudev-testbed
 create mode 100644 src/test/libudev-testbed.c
Makefile.am +27 -0
index 70b8b09..e4b8166 100644
@@ -104,6 +104,7 @@ check_PROGRAMS =
 check_DATA =
 noinst_PROGRAMS =
 TESTS =
+TESTS_ENVIRONMENT = LD_LIBRARY_PATH=.libs:$$LD_LIBRARY_PATH src/test/libudev-testbed
 udevlibexec_PROGRAMS =
 
 AM_CPPFLAGS = \
@@ -1508,6 +1509,32 @@ libudev_private_la_LIBADD = \
 	libsystemd-shared.la
 
 # ------------------------------------------------------------------------------
+
+lib_LTLIBRARIES += \
+	libudev-testbed.la
+
+libudev_testbed_la_SOURCES = \
+	src/test/libudev-testbed.c
+
+libudev_testbed_la_CFLAGS = \
+	$(AM_CFLAGS) \
+	-fvisibility=default
+
+libudev_testbed_la_LDFLAGS = \
+	$(AM_LDFLAGS)
+
+# this is an LD_PRELOAD library, so remove static library and libtool wrappers
+libudev-testbed-install-hook:
+	rm $(DESTDIR)$(libdir)/libudev-testbed.a
+	rm $(DESTDIR)$(libdir)/libudev-testbed.la
+
+INSTALL_EXEC_HOOKS += \
+	libudev-testbed-install-hook
+
+bin_SCRIPTS = \
+	src/test/libudev-testbed
+
+# ------------------------------------------------------------------------------
 MANPAGES += \
 	man/udev.7 \
 	man/udevadm.8 \
src/test/libudev-testbed new file +5 -0
new file mode 100755
index 0000000..44b8258
@@ -0,0 +1,5 @@
+#!/bin/sh
+# Wrapper program to preload the libudev-testbed shared library, so that test
+# programs can set $UDEV_TEST_PREFIX for redirecting sysfs and other queries to
+# a test bed.
+env LD_PRELOAD=libudev-testbed.so.0:$LD_PRELOAD "$@"
src/test/libudev-testbed.c new file +214 -0

214 lines not on this page · raw message

Signature · 1 line
1.7.10.4

From 2b76a9b27c730864eafd7e83848e04e39af4fa2a Mon Sep 17 00:00:00 2001
From: Martin Pitt <[email protected]>
Date: Fri, 6 Jul 2012 13:27:51 +0200
Subject: [PATCH 2/2] gudev: Add GUdevTestbed

The GUdevTestbed class is used to build a temporary sysfs file system. You can add a number of devices including arbitrary sysfs attributes and udev properties, and then run a gudev client in that test bed that is independent of the actual hardware it is running on. With this you can simulate particular hardware in virtual environments up to some degree (e. g. sysctls will fail).

Also add a test-gudev check which tests both GUDev itself and GUdevTestbed.

---
 .gitignore                    |    1 +
 Makefile.am                   |   25 ++-
 docs/gudev/gudev-docs.xml     |    1 +
 docs/gudev/gudev-sections.txt |   24 +++
 src/gudev/gudev.h             |    1 +
 src/gudev/gudevtestbed.c      |  456 +++++++++++++++++++++++++++++++++++++++++
 src/gudev/gudevtestbed.h      |  103 ++++++++++
 src/gudev/gudevtypes.h        |    1 +
 src/test/test-gudev.c         |  248 ++++++++++++++++++++++
 9 files changed, 859 insertions(+), 1 deletion(-)
 create mode 100644 src/gudev/gudevtestbed.c
 create mode 100644 src/gudev/gudevtestbed.h
 create mode 100644 src/test/test-gudev.c
.gitignore +1 -0
index 0732176..1109778 100644
@@ -123,3 +123,4 @@ stamp-*
 /v4l_id
 /test-libudev
 /test-udev
+/test-gudev
Makefile.am +24 -1
index e4b8166..8435592 100644
@@ -1829,6 +1829,7 @@ libgudev_include_HEADERS = \
 	src/gudev/gudevtypes.h \
 	src/gudev/gudevclient.h \
 	src/gudev/gudevdevice.h \
+	src/gudev/gudevtestbed.h \
 	src/gudev/gudevenumerator.h
 
 lib_LTLIBRARIES += libgudev-1.0.la
@@ -1853,6 +1854,8 @@ libgudev_1_0_la_SOURCES = \
 	src/gudev/gudevdevice.c \
 	src/gudev/gudevenumerator.h \
 	src/gudev/gudevenumerator.c \
+	src/gudev/gudevtestbed.h \
+	src/gudev/gudevtestbed.c \
 	src/gudev/gudevprivate.h
 
 nodist_libgudev_1_0_la_SOURCES = \
@@ -1947,7 +1950,10 @@ src_gudev_GUdev_1_0_gir_FILES = \
 	$(top_srcdir)/src/gudev/gudevenumerator.h \
 	$(top_srcdir)/src/gudev/gudevclient.c \
 	$(top_srcdir)/src/gudev/gudevdevice.c \
-	$(top_srcdir)/src/gudev/gudevenumerator.c
+	$(top_srcdir)/src/gudev/gudevenumerator.c \
+	$(top_srcdir)/src/gudev/gudevtestbed.h \
+	$(top_srcdir)/src/gudev/gudevtestbed.c \
+	$(NULL)
 
 INTROSPECTION_GIRS = src/gudev/GUdev-1.0.gir
 INTROSPECTION_SCANNER_ARGS = --c-include=gudev/gudev.h
@@ -1976,6 +1982,23 @@ libgudev-install-move-hook:
 libgudev-uninstall-move-hook:
 	rm -f $(DESTDIR)$(rootlibdir)/libgudev-1.0.so*
 
+noinst_PROGRAMS += \
+	test-gudev
+
+test_gudev_SOURCES = \
+	src/test/test-gudev.c
+
+test_gudev_CFLAGS = \
+	$(GLIB_CFLAGS)
+
+test_gudev_LDADD = \
+	libgudev-1.0.la \
+	$(GLIB_LIBS)
+
+TESTS += \
+	test-gudev
+
+
 INSTALL_EXEC_HOOKS += libgudev-install-move-hook
 UNINSTALL_EXEC_HOOKS += libgudev-uninstall-move-hook
 endif
docs/gudev/gudev-docs.xml +1 -0
index 3e7e50a..43cc9cb 100644
@@ -26,6 +26,7 @@
     <xi:include href="xml/gudevclient.xml"/>
     <xi:include href="xml/gudevdevice.xml"/>
     <xi:include href="xml/gudevenumerator.xml"/>
+    <xi:include href="xml/gudevtestbed.xml"/>
   </chapter>
 
   <chapter id="gudev-hierarchy">
docs/gudev/gudev-sections.txt +24 -0
index b25c13b..ab2ccfb 100644
@@ -98,3 +98,27 @@ G_UDEV_ENUMERATOR_GET_CLASS
 <SUBSECTION Private>
 GUdevEnumeratorPrivate
 </SECTION>
+
+<SECTION>
+<FILE>gudevtestbed</FILE>
+<TITLE>GUdevTestbed</TITLE>
+GUdevTestbed
+GUdevTestbedClass
+g_udev_testbed_new
+g_udev_testbed_add_device
+g_udev_testbed_add_devicev
+g_udev_testbed_get_root_dir
+g_udev_testbed_get_sys_dir
+g_udev_testbed_set_attribute
+g_udev_testbed_set_property
+<SUBSECTION Standard>
+g_udev_testbed_get_type
+G_UDEV_IS_TESTBED
+G_UDEV_IS_TESTBED_CLASS
+G_UDEV_TESTBED
+G_UDEV_TESTBED_CLASS
+G_UDEV_TESTBED_GET_CLASS
+G_UDEV_TYPE_TESTBED
+<SUBSECTION Private>
+GUdevTestbedPrivate
+</SECTION>
src/gudev/gudev.h +1 -0
index 6ae01f2..a8f9102 100644
@@ -28,6 +28,7 @@
 #include <gudev/gudevclient.h>
 #include <gudev/gudevdevice.h>
 #include <gudev/gudevenumerator.h>
+#include <gudev/gudevtestbed.h>
 #undef _GUDEV_INSIDE_GUDEV_H
 
 #endif /* __G_UDEV_H__ */
src/gudev/gudevtestbed.c new file +456 -0

456 lines not on this page · raw message

src/gudev/gudevtestbed.h new file +103 -0

103 lines not on this page · raw message

src/gudev/gudevtypes.h +1 -0
index 8884827..f97751e 100644
@@ -33,6 +33,7 @@ G_BEGIN_DECLS
 typedef struct _GUdevClient GUdevClient;
 typedef struct _GUdevDevice GUdevDevice;
 typedef struct _GUdevEnumerator GUdevEnumerator;
+typedef struct _GUdevTestbed GUdevTestbed;
 
 /**
  * GUdevDeviceNumber:
src/test/test-gudev.c new file +248 -0

248 lines not on this page · raw message

Signature · 1 line
1.7.10.4