From a5ab34509d8a52c37ab6c9c5d5f3501b61bd8d0e Mon Sep 17 00:00:00 2001 From: Alice Frosi Date: Wed, 21 Dec 2022 15:22:37 +0100 Subject: integration: create integration tests Create initial pytest suite for testing seitan and seitan-eater setup. The test suite includes: - 'test_simple' verifies the basic functionalities and the synchronization between seitan and the eater - 'test_restart_seitan' verifies when steitan needs to restart Seitan and eater are deployed in a container to control the environment where they run. Signed-off-by: Alice Frosi --- Makefile | 9 ++ containerfiles/tests/eater/Containerfile | 14 ++++ containerfiles/tests/seitan/Containerfile | 4 + requirements.txt | 3 + tests/integration/seitan_containers.py | 131 ++++++++++++++++++++++++++++++ 5 files changed, 161 insertions(+) create mode 100644 containerfiles/tests/eater/Containerfile create mode 100644 containerfiles/tests/seitan/Containerfile create mode 100644 requirements.txt create mode 100755 tests/integration/seitan_containers.py diff --git a/Makefile b/Makefile index 4a1b444..526e407 100644 --- a/Makefile +++ b/Makefile @@ -33,6 +33,15 @@ numbers.h: test-unit: $(MAKE) -C tests/unit +build-test-images: build seitan seitan-eater + $(MAKE) -C tests-utils + ./build test.bpf + sudo podman build -t test-seitan -f containerfiles/tests/seitan/Containerfile . + sudo podman build -t test-eater -f containerfiles/tests/eater/Containerfile . + +test-integration: + python -m pytest tests/integration/seitan_containers.py + transform.h: qemu_filter ./transform.sh qemu_filter diff --git a/containerfiles/tests/eater/Containerfile b/containerfiles/tests/eater/Containerfile new file mode 100644 index 0000000..53e5b1c --- /dev/null +++ b/containerfiles/tests/eater/Containerfile @@ -0,0 +1,14 @@ +FROM fedora:37 + +RUN mkdir -p /var/run/test-filters + +COPY ./seitan-eater /usr/bin/seitan-eater +COPY ./tests-utils/test-syscalls /usr/local/bin/test-syscalls +# Filter without syscalls +COPY ./test.bpf /var/run/test-filters/test.bpf + +# Make all test filter files reable by all users +RUN chmod -R 0777 /var/run/test-filters && \ + chmod 0777 /var/run/test-filters/* + +ENTRYPOINT ["/usr/bin/seitan-eater"] diff --git a/containerfiles/tests/seitan/Containerfile b/containerfiles/tests/seitan/Containerfile new file mode 100644 index 0000000..e185388 --- /dev/null +++ b/containerfiles/tests/seitan/Containerfile @@ -0,0 +1,4 @@ +FROM fedora:37 + +COPY ./seitan /usr/bin/seitan +COPY ./tests-utils/test-server /usr/local/bin/test-server diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..759bdd2 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +podman==4.3.0 +pytest==7.2.1 +waiting==1.4.1 diff --git a/tests/integration/seitan_containers.py b/tests/integration/seitan_containers.py new file mode 100755 index 0000000..a3cff8b --- /dev/null +++ b/tests/integration/seitan_containers.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python3 + +from podman import PodmanClient +from podman.domain.containers import Container +from podman import errors +from waiting import wait, TimeoutExpired +import pytest +import time + +# The test requires podman root as seitan needs privileged capabilities +uri = "unix:///run/podman/podman.sock" +eater_image = "test-eater:latest" +seitan_image = "test-seitan:latest" + +class ContainerConfig: + def __init__(self, seitan, eater, + exit_code_seitan, exit_code_eater, error_seitan, error_eater, + process, proc_args = []): + self.client = PodmanClient(base_url=uri) + self.exit_code_seitan = exit_code_seitan + self.exit_code_eater = exit_code_eater + self.error_seitan = error_seitan + self.error_eater = error_eater + + # Create eater container + self.eater = self.client.containers.run(eater_image, + name = eater, + detach = True, + user = "1000", + tty = True, + command = ["/usr/bin/seitan-eater", + "-i", + "/var/run/test-filters/test.bpf", + "--", + process] + proc_args) + res = self.eater.inspect() + pid = (res["State"]["Pid"]) + if not isinstance(pid, int): + sys.exit("pid isn't an integer:", pid) + + # Create seitan container + self.seitan = self.client.containers.run(seitan_image, + name = seitan, + detach = True, + tty = True, + remove = True, + pid_mode = "host", + network_mode= "host", + privileged = True, + command = [ "/usr/bin/seitan", + "-p", str(pid), + # TODO: replace /dev/null with input file + "-i", "/dev/null"]) + def wait_containers_creation(self): + self.eater.wait(interval="2s") + self.seitan.wait(interval="2s") + + def wait_container_terminate(self): + def check_container_status(container: "Container"): + if(container.inspect()["State"]["Status"]) == "exited": + return True + return False + wait(lambda: check_container_status(self.eater), timeout_seconds=5) + + def print_logs(self): + print("Output seitan:") + self.seitan.logs() + print("Output eater:") + self.eater.logs() + + def check_results(self): + self.wait_containers_creation() + self.wait_container_terminate() + self.print_logs() + print("Got:", self.seitan.inspect() ["State"]["ExitCode"], "Expected:", self.exit_code_seitan) + assert (self.seitan.inspect() ["State"]["ExitCode"]) == self.exit_code_seitan + assert (self.eater.inspect()["State"]["ExitCode"]) == self.exit_code_eater + assert (self.seitan.inspect()["State"]["Error"]) == self.error_seitan + assert (self.eater.inspect()["State"]["Error"]) == self.error_eater + + def restart_seitan(self): + self.seitan.restart() + + def stop_eater(self): + self.eater.stop() + +def clean_up_containers(containers = []): + with PodmanClient(base_url=uri) as client: + for c in containers: + client.containers.remove(c, force = True) + +@pytest.fixture() +def seitan_container(request): + return "seitan_"+request.node.name + +@pytest.fixture() +def eater_container(request): + return "eater_"+request.node.name + +@pytest.fixture(autouse=True) +def setup(seitan_container, eater_container): + try: + clean_up_containers([seitan_container,eater_container]) + except errors.exceptions.NotFound as e: + print("No previous container existing") + yield + try: + print("Delete ", seitan_container, eater_container) + clean_up_containers([seitan_container,eater_container]) + except errors.exceptions.NotFound as e: + print("Containers already be removed") + + +def test_simple(seitan_container, eater_container): + test = ContainerConfig(seitan=seitan_container, eater=eater_container, + exit_code_seitan=0, exit_code_eater=0, + error_seitan="", error_eater= "", + process = "true") + test.check_results() + +def test_restart_seitan(seitan_container, eater_container): + test = ContainerConfig(seitan=seitan_container, eater=eater_container, + exit_code_seitan=0, exit_code_eater=137, + error_seitan="", error_eater= "", + process = "sleep", proc_args = ["1000"]) + # Give seitan some time to unblock the eater + # TODO: find a better way to detect that sleep has started + time.sleep(10) + test.restart_seitan() + test.stop_eater() + test.check_results() -- cgit v1.2.3