Hi,

PKGBUILDs include the check() function which allows one to run tests on the 
software after it has been built, but before it has been packaged.
This message proposes to add a test() function, which essentially allows to run 
tests after package(), and in particular after the package has been installed 
in a chroot (for these testing purposes).

This allows the packager to run tests against the final installation (or as 
final as can be in a chroot). Between package() and test(), the resulting pkg 
is installed in a chroot like on the regular system (i.e. /usr/bin instead of 
$pkgdir/usr/bin). Everything but the pkg files and the test files is removed, 
so only the installation is under test.

The idea for this came from the issue that Python packages usually don't need a 
build or rather, that that build can't be tested without fully installing it. 
This installation however isn't really possible since /usr/ is inaccessible for 
obvious reasons. Workarounds usually involve setting the PYTHONPATH, but that's 
tedious at best and ultimately unnecessary.
Because Python has an extensive auto-detection of libraries and dependencies, 
the tests can be executed easily, if Python can find them. And after 
installation (in /usr/lib/python*/site-packages/), the package is easily found. 
This of course is in contrast to most compiled languages, who would require 
lots of paths and links in order to be able to compile the tests. It shouldn't 
be this way, but it is.

A slight complication arises from the fact that tests can theoretically be 
anywhere in the python source code. So either makepkg figures out what is a 
test, or the packager specifies that. In most cases though, all tests are in a 
single directory, and the edge cases are vast, so the latter case with some 
boilerplate is probably better.

In total, a PKGBUILD might look something like this (names are subject to 
change):
```
build() {
  cd ${pkgname}-${pkgver}/
  python -m build --wheel --no-isolation
}

check() {
  cd ${pkgname}-${pkgver}/
  python -m pytest
}

package() {
  cd ${pkgname}-${pkgver}/
  python -m installer --destdir="$pkgdir" dist/*.whl
}

collect() {
  cd ${pkgname}-${pkgver}/
  # collects the tests and puts them into $testdir
  python -m pytest --co | grep -o "[^ ]*\.py" | xargs cp -t $testdir
}

# inbetween collect() and test(), the package is installed in the chroot and 
$testdir is copied

test() {
  # we are in $testdir (e.g. /home/builduser)
  pytest
}
```
Notice the line in collect() which is responsible to collect the tests. We 
basically ask pytest what it wants to run, then filter out the files, and 
lastly copy them into $testdir, which is ultimately copied over and run.
In most cases, this line might just be something like `cp tests/ $testdir/`.

------------
Makepkg
------------

This post is already quite long, so I'll make it quick with some implementation 
thoughts.

Since collect() and test() always run together or don't run together (test() 
needs collect() and only collect() has no effect), only a single option is 
necessary to toggle whether to run the post-package tests.
The order of package() and collect() conceptually doesn't matter, but collect() 
should probably run after to guarantee that it does not influence package(). 
Either case, the packager is responsible.
This is a pure addition, so if collect() and test() are missing, then just 
nothing happens. If only collect() is implemented, that might be ignored too. 
If only test() exists, then an error is probably most helpful, since no 
packages are copied. Alternatively, maybe makepkg does some limited test 
identification (like looking for tests/ folder). Or just nothing happens 
because the packager made a mistake. Should be obvious enough.


In conclusion, two new methods are introduced to allow for better and more 
precise testing of the final output, as well as easier testing in case of 
Python.
The first function - collect() - collects all the tests in the codebase and 
copies them into $testdir, while package() creates the pkg in $pkgdir. After 
that, a chroot with all depends packages is created and the pkg installed 
therein. $testdir is also copied there. Lastly, the second function - test() - 
is called and executed to test the installation.

Thanks for your attention, if you have further ideas or questions, I'd like to 
hear them.
If something similar has already been discussed, feel free to point out that 
thread. AFAICT, it hasn't been before.

- Lamarrrk

Reply via email to