A quick post on testing Singularity builds, where I discovered how the %test
section of the Singularity Definition File works. If you aren't familiar, the Definition File is similar to the Dockerfile for Docker; it is used to define and build the image. From the documentation:
A SingularityCE Definition File (or “def file” for short) is like a set of blueprints explaining how to build a custom container. It includes specifics about the base OS to build or the base container to start from, as well as software to install, environment variables to set at runtime, files to add from the host system, and container metadata.
There is a test section, which as described in the documentation:
The %test section runs at the very end of the build process, and can be used to validate the container using methods of your choosing. You can also execute this scriptlet through the container itself, using the test command.
Here's an example from the documentation
%test
grep -q NAME=\"Ubuntu\" /etc/os-release
if [ $? -eq 0 ]; then
echo "Container base is Ubuntu as expected."
else
echo "Container base is not Ubuntu."
exit 1
fi
However, it wasn't obvious to me that this section will not fail even with a failing command. For example, the following def file will build.
Bootstrap: docker
From: debian:bullseye-slim
%runscript
exec /usr/local/bin/hello.sh
%post
printf '#!/usr/bin/env bash\necho Hi there\n' > /usr/local/bin/hello.sh \
&& chmod 755 /usr/local/bin/hello.sh
%test
laksdjf
echo $?
/usr/local/bin/hello.sh
INFO: Starting build...
INFO: Running post scriptlet
+ printf #!/usr/bin/env bash\necho Hi there\n
+ chmod 755 /usr/local/bin/hello.sh
INFO: Adding runscript
INFO: Adding testscript
INFO: Running testscript
/.singularity.d/test: 3: laksdjf: not found
127
Hi there
INFO: Creating SIF file...
INFO: Build complete: blah.sif
I was writing tests line by line in the %test
section and didn't realise that my tests had failed because the image was built. My solution was then to chain each test using &&
, which worked.
Only later I realised that the %test section works like a script when I saw the following example from the documentation:
%test
#!/bin/zsh
echo "$(readlink /proc/$$/exe) is our shell"
Therefore, another way to catch errors when using Bash is to use set -e
, which will exit when any command in the script fails.
Bootstrap: docker
From: debian:bullseye-slim
%runscript
exec /usr/local/bin/hello.sh
%post
printf '#!/usr/bin/env bash\necho Hi there\n' > /usr/local/bin/hello.sh \
&& chmod 755 /usr/local/bin/hello.sh
%test
/bin/bash
set -e
laksdjf
echo $?
/usr/local/bin/hello.sh
INFO: Starting build...
INFO: Running post scriptlet
+ printf #!/usr/bin/env bash\necho Hi there\n
+ chmod 755 /usr/local/bin/hello.sh
INFO: Adding runscript
INFO: Adding testscript
INFO: Running testscript
/.singularity.d/test: 5: laksdjf: not found
FATAL: While performing build: failed to execute %test script: exit status 127
This work is licensed under a Creative Commons
Attribution 4.0 International License.