Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor python tests #740

Merged
merged 3 commits into from
Feb 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion tests/test_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ def test_general_labels(
if version == "tumbleweed":
assert OS_VERSION in labels[f"{prefix}.version"]

expected_url: Tuple[str] = (
expected_url: Tuple[str, ...] = (
"https://www.suse.com/products/base-container-images/",
) + (
("https://www.suse.com/products/server/",)
Expand Down
177 changes: 62 additions & 115 deletions tests/test_python.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
"""Basic tests for the Python base container images."""

import time
import hashlib

import packaging.version
import pytest
import requests
from pytest_container import DerivedContainer
from pytest_container import OciRuntimeBase
from pytest_container import PortForwarding
from pytest_container.container import ContainerData
from pytest_container.container import ImageFormat
from pytest_container.container import container_and_marks_from_pytest_param
from pytest_container.runtime import LOCALHOST
from pytest_container.runtime import Version
Expand All @@ -25,48 +26,65 @@
OUTDIR = "output/"
APPL1 = "tensorflow_examples.py"
PORT1 = 8123
t0 = time.time()

# copy tensorflow module trainer from the local application directory to the container
DOCKERF_PY_T1 = f"""
WORKDIR {BCDIR}
EXPOSE {PORT1}
"""

DOCKERF_PY_T2 = f"""
WORKDIR {BCDIR}
RUN mkdir {APPDIR}
RUN mkdir {OUTDIR}
EXPOSE {PORT1}
COPY {ORIG + APPDIR}/{APPL1} {APPDIR}
"""

#: Base containers under test, input of auto_container fixture
CONTAINER_IMAGES = PYTHON_CONTAINERS + SAC_PYTHON_CONTAINERS


#: Derived containers, from custom Dockerfile including additional test files
#: and extra args, input to container_per_test fixture
CONTAINER_IMAGES_T1 = [
#: Derived containers with the python http.server as CMD and a HEALTHCHECK
#: ensuring that the server is up and running
HTTP_SERVER_CONTAINER_IMAGES = [
pytest.param(
DerivedContainer(
base=container_and_marks_from_pytest_param(CONTAINER_T)[0],
containerfile=DOCKERF_PY_T1,
containerfile=f"""RUN zypper -n in iproute2 curl && zypper -n clean
CMD python3 -m http.server {PORT1}
HEALTHCHECK --interval=10s --timeout=1s --retries=10 CMD curl -sf http://localhost:{PORT1}
""",
forwarded_ports=[PortForwarding(container_port=PORT1)],
image_format=ImageFormat.DOCKER,
),
marks=CONTAINER_T.marks,
id=CONTAINER_T.id,
)
for CONTAINER_T in CONTAINER_IMAGES
]

REQUESTS_CONTAINER_IMAGES = [
pytest.param(
DerivedContainer(
base=container_and_marks_from_pytest_param(param)[0],
containerfile=f"""WORKDIR {BCDIR}
RUN python3 -m venv .venv; source .venv/bin/activate; pip install requests
""",
),
marks=param.marks,
id=param.id,
)
for param in CONTAINER_IMAGES
]

#: URL of the SLE BCI Logo
SLE_BCI_LOGO_URL = "https://opensource.suse.com/bci/SLE_BCI_logomark_green.svg"

#: sha512 hexdigest of the SLE BCI Logo, output of
#: :command:`curl $SLE_BCI_LOGO_URL|sha512sum`
SLE_BCI_LOGO_SHA512_SUM = "6b4447f88be45ae335868b8c4c0200adfc26b85359cfa74965388571c51b4611454c9fb3d386c61d9bc312b5dad0a71dc3753303338a88db7bfdc8f94ac114a1"

#: Derived containers, from custom Dockerfile including additional test files,
#: input to container_per_test fixture
CONTAINER_IMAGES_T2 = [
TENSORFLOW_CONTAINER_IMAGES = [
pytest.param(
DerivedContainer(
base=container_and_marks_from_pytest_param(CONTAINER_T)[0],
containerfile=DOCKERF_PY_T2,
containerfile=f"""
WORKDIR {BCDIR}
RUN mkdir {APPDIR}
RUN mkdir {OUTDIR}
EXPOSE {PORT1}
COPY {ORIG + APPDIR}/{APPL1} {APPDIR}
""",
),
marks=CONTAINER_T.marks,
id=CONTAINER_T.id,
Expand Down Expand Up @@ -207,113 +225,42 @@ def test_pip_install_source_cryptography(auto_container_per_test):
reason="server port checks not compatible with old podman versions 1.x",
)
@pytest.mark.parametrize(
"container_per_test", CONTAINER_IMAGES_T1, indirect=["container_per_test"]
"container_per_test", HTTP_SERVER_CONTAINER_IMAGES, indirect=True
)
@pytest.mark.parametrize("hmodule, retry", [("http.server", 10)])
def test_python_webserver_1(
container_per_test: ContainerData, hmodule: str, retry: int
) -> None:
def test_python_http_server_module(container_per_test: ContainerData) -> None:
"""Test that the python webserver is able to open a given port"""

portstatus = False
t = 0
port = container_per_test.forwarded_ports[0].host_port

command = f"timeout --preserve-status 120 python3 -m {hmodule} {port} &"
ctr_port = container_per_test.forwarded_ports[0].container_port
host_port = container_per_test.forwarded_ports[0].host_port

# pkg needed to run socket/port check
if not container_per_test.connection.package("iproute2").is_installed:
container_per_test.connection.run_expect([0], "zypper -n in iproute2")

# checks that the expected port is Not listening yet
assert not container_per_test.connection.socket(
f"tcp://0.0.0.0:{port}"
assert container_per_test.connection.socket(
f"tcp://0.0.0.0:{ctr_port}"
).is_listening

t1 = time.time() - t0

# start of the python http server
container_per_test.connection.run_expect([0], command)
resp = requests.get(f"http://0.0.0.0:{host_port}", timeout=10)
resp.raise_for_status()
assert resp.text

t2 = time.time() - t0

# port status inspection with timeout
for _ in range(retry):
time.sleep(1)
portstatus = container_per_test.connection.socket(
f"tcp://0.0.0.0:{port}"
).is_listening

if portstatus:
break

t3 = time.time() - t0

# check inspection success or timeout
assert portstatus, (
"Timeout expired: expected port not listening. Time marks: before "
+ f"server start {t1}s, after start {t2}s, after {t} loops {t3}s."
)


@pytest.mark.skipif(
OS_VERSION == "tumbleweed",
reason="pip --user not working due to PEP 668",
)
@pytest.mark.parametrize(
"container_per_test", CONTAINER_IMAGES_T2, indirect=["container_per_test"]
"container_per_test", REQUESTS_CONTAINER_IMAGES, indirect=True
)
@pytest.mark.parametrize(
"destdir, appl2, url, xfilename",
[
(
BCDIR + OUTDIR,
"communication_examples.py",
"https://opensource.suse.com/bci/SLE_BCI_logomark_green.svg",
"SLE_BCI_logomark_green.svg",
)
],
)
def test_python_webserver_2(
container_per_test: ContainerData,
host,
container_runtime: OciRuntimeBase,
destdir: str,
appl2: str,
url: str,
xfilename: str,
) -> None:
"""Test that the python `wget <https://pypi.org/project/wget/>`_ library,
coded in the appl2 module, is able to fetch files from a webserver
"""
def test_python_fetch_remote_file(container_per_test: ContainerData) -> None:
"""Test that python's requests is able to fetch the SLE_BCI logo from
opensource.suse.com

# install wget for python
container_per_test.connection.run_expect([0], "pip install wget")

# copy an application file from the local test-server into the running
# container under test
host.check_output(
f"{container_runtime.runner_binary} cp {ORIG + APPDIR + appl2} "
f"{container_per_test.container_id}:{BCDIR + APPDIR}",
"""
logo_text: str = container_per_test.connection.check_output(
"source .venv/bin/activate; "
f"python -c \"import requests; resp = requests.get('{SLE_BCI_LOGO_URL}', timeout=120); "
'resp.raise_for_status(); print(resp.text)"'
)

# check the test python module is present in the container
assert container_per_test.connection.file(BCDIR + APPDIR + appl2).is_file

# check expected file not present yet in the destination
assert not container_per_test.connection.file(destdir + xfilename).exists

# execution of the python module in the container
bci_python_wget = container_per_test.connection.check_output(
f"timeout --preserve-status 120s python3 {APPDIR + appl2} {url} {destdir}",
assert (
dcermak marked this conversation as resolved.
Show resolved Hide resolved
hashlib.sha512(logo_text.encode("utf-8")).hexdigest()
== SLE_BCI_LOGO_SHA512_SUM
)

# run the test in the container and check expected keyword from the module
assert "PASS" in bci_python_wget

# check expected file present in the bci destination
assert container_per_test.connection.file(destdir + xfilename).exists


@pytest.mark.skipif(
OS_VERSION == "tumbleweed",
Expand All @@ -325,7 +272,7 @@ def test_python_webserver_2(
reason="Tensorflow python library tested on x86_64",
)
@pytest.mark.parametrize(
"container_per_test", CONTAINER_IMAGES_T2, indirect=["container_per_test"]
"container_per_test", TENSORFLOW_CONTAINER_IMAGES, indirect=True
)
def test_tensorf(container_per_test):
"""Test that the python tensorflow library, coded in the appl1 module,
Expand Down
57 changes: 0 additions & 57 deletions tests/trainers/communication_examples.py

This file was deleted.

Loading