By SAn
Some people that have been writing about unit testing in lua, and also about lua for embedded:
The set of requirements for the LibreMesh project in regards of testing are the following:
We need to consider unit testing, mocking and coverage tests.
There is a list of unittesting libraries in the lua package manager, luarocks:
https://luarocks.org/labels/test?non_root=on
These are the ones analyzed:
URL: https://github.com/bluebird75/luaunit
Upsides:
Downsides:
They describe themselves as a A highly customizable test library for Lua that allows declarative tests with nested contexts.
URL: https://github.com/norman/telescope/
Last release 2013. Lua 5.1 last release was done in 2012, so it is not that big of a deal… but has not received any updates since, so it might have not evolved since.
URL:
Upsides:
Downsides:
URL: https://github.com/henry4k/lua-mock
URL: https://github.com/ryanplusplus/mach.lua/
More or less well maintain, though it is not so popular.
URL: https://github.com/keplerproject/luacov
Upsides:
The idea is to allow unit-testing packages and also the integration between them as some of the packages depend on other packages.
Context:
This context is not an easy one to test as it has a lot of trade offs!
The easiest architecture is to have a global tests directory and some utility functions that allow to "install" a certain module for testing
Directory structure:
lime-packages/package/package1/
lime-packages/package/package1/...
lime-packages/package/package2
lime-packages/package/package2/...
lime-packages/tests/utils.lua
lime-packages/tests/fake_modules/nixio.fs
lime-packages/tests/test_package_1.lua
lime-packages/tests/test_package_2.lua
lime-packages/tests/test_package_1_and_2_integration.lua
lime-packages/run_tests.sh
Example of a (integration) test that uses libraries and fake modules
test_lime_proto_anygw.lua:
Pros:
Cons:
Directory structure:
lime-packages/package/package1/
lime-packages/package/package1/tests/test_foo.lua
lime-packages/package/package2
lime-packages/package/package2/tests/test_bar.lua
lime-packages/tests/utils.lua
lime-packages/tests/fake_modules/nixio.fs
lime-packages/tests/test_package_1_and_2_integration.lua
lime-packages/run_tests.sh
Pros:
Cons:
Tests can be run installing all files of the packages (by some script that parses the Makefiles, or "by hand in a helper script").
Pros:
Cons:
Executable lua modules can be tested with a simple modification in the file creating a main() function and then using something like:
Then from a test file it can be loaded like any normal module and all the functions can be accesed without executing main()
A docker environment (or multiple, even using "qemu-user" under docker) with the testing libraries and target lua version is loaded by the "run_tests.sh" executable.
This environment can provide some useful libraries for testing (coverage reporting,
Direct import and testing can be done for unit tests were functions are not using system libraries, or when these are simple enough to be mockable (mocking shell() calls).
described by this guy, thanks!
We did a trial to run busted inside a router… that would have been useful for in-router tests and also for tests inside a virtual environment.
It used the strategy of installing luarocks dependencies in a separate directory and copying them to the router.
The steps are pretty straightforward:
The output of this command though was not what we expected:
Deeper inspection showed that the library's dependencies had C bindings that we compiled for a different arquitecture, so tha strategy was not feasable for routers anymore:
where term/core.so and system/core.so are system libs, but lfs.so is from LuaFileSystem.
There is a lua-only implementation of LuaFileSystem: https://github.com/sonoro1234/luafilesystem , but as it doesn't support luarocks deeper understanding of the platform is needed to attempt to replace the only binary binding with this implementation.
Found a sister library from that one in luarocks: https://luarocks.org/modules/3scale/luafilesystem-ffi based on this repo: https://github.com/spacewander/luafilesystem. So:
installed it and then touched the code were the penlight library was imported in busted:
but this library, as it depends on ffi (a module of luajit), it depends on a C extension too.
also, luafilesystem exists as a native library in OpenWRT, so it could be included just for the sake of the exercise: https://openwrt.org/packages/pkgdata/luafilesystem … but not this time.
Some docker images already exist:
A simple Dockerfile whould be:
Excellent blog post on handling Lua paths: http://www.thijsschreijer.nl/blog/?p=1025
Example of LUA_PATH to load executables (without ending in .lua): LUA_PATH="packages/safe-upgrade/files/usr/sbin/?;;"
. The double ;;
at the end means append the default paths.
I selected safe-uprgade
libremesh module to start doing unittests because I know the module as I wrote it so I already know which code would gain value being tested. Also I am confident to refactor the module if needed.
First I start using the busted
unittest library with a simple test of the function get_current_partition()
that must return the partition number that is currently running. As this is done from reading /proc/mtd
I refactored the function so we can pass from the outside the expected content.
Content of lime-packages/safe-upgrade/tests/test_safe_upgrade.lua
:
The modifications I did to do to the safe-upgrade
module are:
get_current_partition()
into get_proc_mtd()
and get_current_partition(proc_mtd)
. This way we can inject different /proc/mtd
values for testing.get_current_partition
.parse_args
function that only gets executed when the module is run in script mode (not library mode)This changes may not be the best way of handling testing but for now it allow us to move forward without digging a hole too deep:
To run the test inside the docker container we have to add the module under test to the LUA_PATH (check that it is an executable module that does not ends with .lua
so the expresion is ?
instead of ?.lua
):
busted
or luaunit
. We are selecting busted
as it has more pros than luaunit, mainly integrated mocking and coverage.