Write Integration Tests for the Scripts

Kiwi ships a set of helper functions that can be used in config.sh (see also: User Defined Scripts). These utilize containers to run the individual functions and verify that they resulted in the desired state.

Ensure that you have either podman or docker installed and configured on your system. The integration tests will use podman in rootless mode by default, if it is installed on your system. You can select docker instead by setting the environment variable CONTAINER_RUNTIME to docker. Then you can run the integration tests via tox:

$ tox -e scripts -- -n NUMBER_OF_THREADS

It is recommended to leverage testinfra and the shared_container and container_per_test fixtures for writing these integration tests. The fixtures give your test functions a connection to a running container (by default that will be opensuse/tumbleweed) functions.sh copied to /bin/functions.sh inside the container. You can then use the connection to perform some setup, tear down and the actual tests as follows:

def test_RmWorks(shared_container):
    # create the file /root/foobar
    shared_container.run_expect([0], "touch /root/foobar")
    assert shared_container.file("/root/foobar").exists

    # source the functions and execute our function under test
    shared_container.run_expect([0], ". /bin/functions.sh && Rm /root/foobar")

    # verify the result
    assert not shared_container.file("/root/foobar").exists

In this example we used the shared_container fixture: it creates a podman container at the start of the test session and gives each function using this fixture the same connection. Therefore you must only use it for tests where you do not perform any mutation of the container that you are not undoing afterwards! If you need to perform extensive mutation that you cannot or do not want to undo yourself, then resort to the container_per_test fixture. It will give you a fresh container for each test function. While this makes writing tests simpler, it also increases the runtime significantly, thus only use it when necessary.

Running Tests for multiple container images

It is important to test certain functions on multiple operating systems & versions, to e.g. ensure that older tools behave the same way that you expect them to.

This can be achieved by leveraging pytest’s fixture parametrization as follows:

@pytest.mark.parametrize(
    "shared_container",
    (
        "Tumbleweed",
        "Leap-15.3",
    ),
    indirect=True,
)
def test_something(shared_container):
    pass

Where we pass multiple image names to the container images to the shared_container fixture. Pytest will then look for the image with the given name in the predefined list of containers in conftest.py.

To add a new container, simply add a new Container class to the CONTAINERS list and give it appropriate values for name and url.