From 6737b7f825915000ac9786f171dba3469ea4f862 Mon Sep 17 00:00:00 2001 From: "Petr \"Stone\" Hracek" Date: Mon, 22 Sep 2025 13:29:30 +0200 Subject: [PATCH 01/21] Add script for running tests by CI Signed-off-by: Petr "Stone" Hracek --- test/run-pytest | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100755 test/run-pytest diff --git a/test/run-pytest b/test/run-pytest new file mode 100755 index 00000000..e69959ad --- /dev/null +++ b/test/run-pytest @@ -0,0 +1,15 @@ +#!/bin/bash +# +# IMAGE_NAME specifies a name of the candidate image used for testing. +# The image has to be available before this script is executed. +# SINGLE_VERSION specifies the major version of the MariaDB in format of X.Y +# OS specifies RHEL version (e.g. OS=rhel8) +# + +THISDIR=$(dirname ${BASH_SOURCE[0]}) + +PYTHON_VERSION="3.12" +if [[ ! -f "/usr/bin/python$PYTHON_VERSION" ]]; then + PYTHON_VERSION="3.13" +fi +cd "${THISDIR}" && "python${PYTHON_VERSION}" -m pytest -s -rA --showlocals -vv test_container_*.py From 6d5f823c879fa26ac05d0d0f5906c315e4cba276 Mon Sep 17 00:00:00 2001 From: "Petr \"Stone\" Hracek" Date: Mon, 22 Sep 2025 13:30:45 +0200 Subject: [PATCH 02/21] Add container tests for httpd-container Migration matrix is: run_self_cert_test -> test_container_httpd.py (TestHttpdS2ISslSElfSignedAppContainer) run_default_page_test -> test_container_httpd.py (TestHttpdAppContainer.test_default_page) run_as_root_test -> test_container_httpd.py (TestHttpdAppContainer.test_default_page) run_log_to_volume_test -> test_container_httpd.py (TestHttpdAppContainer.test_log_data_volume) run_data_volume_test -> test_container_httpd.py (TestHttpdAppContainer.test_data_volume) run_s2i_test -> test_container_httpd.py (TestHttpdAppContainer.test_run_s2i_usage) run_cert_age_test -> test_container_httpd.py (TestHttpdCertAgeContainer) run_pre_init_test -> test_container_httpd_s2i.py (TestHttpdS2IPreInitContainer) run_mpm_config_test -> test_container_httpd.py (TestHttpdAppContainer.test_mpm_config) run_dockerfiles_test -> test_container_httpd.py (TestHttpdAppContainer.test_dockerfiles) NEW- test_sample_app -> test_container_httpd_s2i.py (TestHttpdS2ISampleAppContainers) Signed-off-by: Petr "Stone" Hracek --- test/test_container_httpd.py | 146 +++++++++++++++++++++++++++++++ test/test_container_httpd_s2i.py | 84 ++++++++++++++++++ test/test_container_ssl.py | 120 +++++++++++++++++++++++++ 3 files changed, 350 insertions(+) create mode 100644 test/test_container_httpd.py create mode 100644 test/test_container_httpd_s2i.py create mode 100644 test/test_container_ssl.py diff --git a/test/test_container_httpd.py b/test/test_container_httpd.py new file mode 100644 index 00000000..f95aaec6 --- /dev/null +++ b/test/test_container_httpd.py @@ -0,0 +1,146 @@ +import os +import sys + +import pytest + +from pathlib import Path + +from container_ci_suite.container_lib import ContainerTestLib +from container_ci_suite.utils import check_variables, ContainerTestLibUtils + + +if not check_variables(): + print("At least one variable from OS, VERSION is missing.") + sys.exit(1) + + +TEST_DIR = Path(os.path.abspath(os.path.dirname(__file__))) +VERSION = os.getenv("VERSION") +OS = os.getenv("OS") +IMAGE_NAME = os.getenv("IMAGE_NAME") +if not IMAGE_NAME: + print(f"Built container for version {VERSION} on OS {OS} does not exist.") + sys.exit(1) +print(f"Test dir is: {TEST_DIR}") + + +@pytest.fixture(scope="module") +def app(request): + app = ContainerTestLib(image_name=IMAGE_NAME, s2i_image=True) + yield app + app.clean_containers() + app.clean_app_images() + + +class TestHttpdAppContainer: + + def test_default_page(self, app): + assert app.create_container(cid_file_name="test_default_page") + cip = app.get_cip("test_default_page") + assert cip + if OS == "c9s" or OS == "c10s": + response = "HTTP Server Test Page" + else: + # The RHEL and Fedora OS gets this response + response = "Test Page for the HTTP Server on" + assert app.test_response(url=f"{cip}", expected_code=403, expected_output=response, max_attempts=3) + + def test_run_as_root(self, app): + assert app.create_container(cid_file_name="test_default_page", container_args="--user 0") + cip = app.get_cip("test_default_page") + assert cip + if OS == "c9s" or OS == "c10s": + response = "HTTP Server Test Page" + else: + response = "Test Page for the HTTP Server on" + assert app.test_response(url=f"{cip}", expected_code=403, expected_output=response, max_attempts=3) + + def test_run_s2i_usage(self, app): + output = app.s2i_usage() + print(f"S2i_USAGE output: '{output}'") + assert output != "" + + @pytest.mark.parametrize( + "dockerfile", + [ + "Dockerfile", + "Dockerfile.s2i" + ] + ) + def test_dockerfiles(self, app, dockerfile): + assert app.build_test_container( + dockerfile=f"{TEST_DIR}/examples/{dockerfile}", app_url="https://github.com/sclorg/httpd-ex.git", + app_dir="app-src" + ) + assert app.test_app_dockerfile() + cip = app.get_cip() + assert cip + assert app.test_response(url=f"{cip}", expected_code=200, expected_output="Welcome to your static httpd application on OpenShift") + + @pytest.mark.parametrize( + "mpm_config", + [ + "worker", + "event", + "prefork", + ] + ) + def test_mpm_config(self, app, mpm_config): + cid_name = f"test_mpm_{mpm_config}" + assert app.create_container(cid_file_name=cid_name, container_args=f"-e HTTPD_MPM={mpm_config} --user 1001") + cip = app.get_cip(cid_file_name=cid_name) + # Let's check that server really response HTTP-403 + # See function here: in test/run `_run_mpm_config_test` + # https://github.com/sclorg/httpd-container/blob/master/test/run#L97 + assert app.test_response(url=f"{cip}", port=8080, expected_code=403, expected_output=".*" ) + logs = app.get_logs(cid_file_name=cid_name) + assert ContainerTestLibUtils.check_regexp_output( + regexp_to_check=f"mpm_{mpm_config}:notice.*resuming normal operations", + logs_to_check=logs + ) + def test_log_to_data_volume(self, app): + data_dir = ContainerTestLibUtils.create_local_temp_dir( + dir_name="/tmp/httpd-test_log_dir" + ) + ContainerTestLibUtils.commands_to_run( + commands_to_run = [ + f"mkdir -p {data_dir}", + f"chown -R 1001:1001 {data_dir}", + f"chcon -Rvt svirt_sandbox_file_t {data_dir}/" + ] + ) + assert app.create_container( + cid_file_name="test_log_dir", + container_args=f"-e HTTPD_LOG_TO_VOLUME=1 --user 0 -v {data_dir}:/var/log/httpd" + ) + cip = app.get_cip(cid_file_name="test_log_dir") + assert app.test_response(url=f"{cip}", port=8080, expected_code=403, expected_output=".*") + assert ContainerTestLibUtils.check_files_are_present( + dir_name=data_dir, file_name_to_check=[ + "access_log", + "error_log", + "ssl_access_log", + "ssl_error_log", + "ssl_request_log", + ] + ) + + def test_data_volume(self, app): + data_dir = ContainerTestLibUtils.create_local_temp_dir( + dir_name="/tmp/httpd-test-volume" + ) + ContainerTestLibUtils.commands_to_run( + commands_to_run = [ + f"mkdir -p {data_dir}/html", + f"echo hello > {data_dir}/html/index.html", + f"chown -R 1001:1001 {data_dir}", + f"chcon -Rvt svirt_sandbox_file_t {data_dir}/" + ] + ) + assert app.create_container( + cid_file_name="doc_root", + container_args=f"-v {data_dir}:/var/www" + ) + cip = app.get_cip(cid_file_name="doc_root") + assert cip + assert app.test_response(url=f"{cip}", port=8080, expected_code=200, expected_output="hello") diff --git a/test/test_container_httpd_s2i.py b/test/test_container_httpd_s2i.py new file mode 100644 index 00000000..5c21d92d --- /dev/null +++ b/test/test_container_httpd_s2i.py @@ -0,0 +1,84 @@ +import os +import sys +import pytest + +from pathlib import Path + +from container_ci_suite.container_lib import ContainerTestLib +from container_ci_suite.utils import check_variables + + +from constants import return_app_name + + +if not check_variables(): + print("At least one variable from OS, VERSION is missing.") + sys.exit(1) + + +TEST_DIR = Path(os.path.abspath(os.path.dirname(__file__))) +VERSION = os.getenv("VERSION") +OS = os.getenv("TARGET") +IMAGE_NAME = os.getenv("IMAGE_NAME") +if not IMAGE_NAME: + print(f"Built container for version {VERSION} on OS {OS} does not exist.") + sys.exit(1) + +image_tag_wo_tag = IMAGE_NAME.split(":")[0] +image_tag = IMAGE_NAME.split(":")[1] +pre_init_test_app = os.path.join(TEST_DIR, "pre-init-test-app") +sample_test_app = os.path.join(TEST_DIR, "sample-test-app") + + +@pytest.fixture(scope="module", params=[pre_init_test_app]) +def s2i_app_pre_init(request): + container_lib = ContainerTestLib(IMAGE_NAME) + app_name = return_app_name(request) + s2i_app = container_lib.build_as_df( + app_path=request.param, + s2i_args="--pull-policy=never", + src_image=IMAGE_NAME, + dst_image=f"{IMAGE_NAME}-{app_name}" + ) + yield s2i_app + s2i_app.clean_containers() + + +@pytest.fixture(scope="module", params=[sample_test_app]) +def s2i_sample_app(request): + ci = ContainerTestLib(IMAGE_NAME) + app_name = return_app_name(request) + s2i_app = ci.build_as_df( + app_path=request.param, + s2i_args="--pull-policy=never", + src_image=IMAGE_NAME, + dst_image=f"{IMAGE_NAME}-{app_name}" + ) + yield s2i_app + s2i_app.clean_containers() + + +class TestHttpdS2IPreInitContainer: + + def test_run_pre_init_test(self, s2i_app_pre_init): + assert s2i_app_pre_init.create_container(cid_file_name=s2i_app_pre_init.app_name, container_args="--user 1000") + cip = s2i_app_pre_init.get_cip(cid_file_name=s2i_app_pre_init.app_name) + assert cip + response = f"This content was replaced by pre-init script." + assert s2i_app_pre_init.test_response(url=f"{cip}", expected_code=200, expected_output=response) + + +class TestHttpdS2ISampleAppContainer: + + def test_sample_app(self, s2i_sample_app): + assert s2i_sample_app.create_container(cid_file_name=s2i_sample_app.app_name, container_args="--user 1000") + cip = s2i_sample_app.get_cip(cid_file_name=s2i_sample_app.app_name) + assert cip + response = "This is a sample s2i application with static content." + assert s2i_sample_app.test_response(url=f"{cip}", expected_code=200, expected_output=response) + assert s2i_sample_app.test_response( + url=f"https://{cip}", + port=8443, + expected_output=response + ) + diff --git a/test/test_container_ssl.py b/test/test_container_ssl.py new file mode 100644 index 00000000..0038779c --- /dev/null +++ b/test/test_container_ssl.py @@ -0,0 +1,120 @@ +import os +import sys +import pytest +import time + +from pathlib import Path + +from container_ci_suite.container_lib import ContainerTestLib +from container_ci_suite.utils import check_variables, ContainerTestLibUtils +from container_ci_suite.engines.podman_wrapper import PodmanCLIWrapper + + +if not check_variables(): + print("At least one variable from OS, VERSION is missing.") + sys.exit(1) + + +TEST_DIR = Path(os.path.abspath(os.path.dirname(__file__))) +VERSION = os.getenv("VERSION") +OS = os.getenv("TARGET") +IMAGE_NAME = os.getenv("IMAGE_NAME") +if not IMAGE_NAME: + print(f"Built container for version {VERSION} on OS {OS} does not exist.") + sys.exit(1) + +image_tag_wo_tag = IMAGE_NAME.split(":")[0] +image_tag = IMAGE_NAME.split(":")[1] +self_cert_test = os.path.join(TEST_DIR, "self-signed-ssl") +sample_test_app = os.path.join(TEST_DIR, "sample-test-app") + +@pytest.fixture(scope="module", params=[sample_test_app]) +def s2i_sample_app(request): + ci = ContainerTestLib(IMAGE_NAME) + app_name = os.path.basename(request.param) + s2i_app = ci.build_as_df( + app_path=request.param, + s2i_args="--pull-policy=never", + src_image=IMAGE_NAME, + dst_image=f"{IMAGE_NAME}-{app_name}" + ) + yield s2i_app + s2i_app.clean_containers() + +@pytest.fixture(scope="module", params=[self_cert_test]) +def ssl_app(request): + ci = ContainerTestLib(IMAGE_NAME) + app_name = os.path.basename(request.param) + s2i_app = ci.build_as_df( + app_path=request.param, + s2i_args="--pull-policy=never", + src_image=IMAGE_NAME, + dst_image=f"{IMAGE_NAME}-{app_name}" + ) + yield s2i_app + s2i_app.clean_containers() + +@pytest.fixture(scope="module") +def app(request): + app = ContainerTestLib(image_name=IMAGE_NAME, s2i_image=True) + yield app + app.clean_containers() + app.clean_app_images() + + +class TestHttpdS2ISslSelfSignedAppContainer: + + def test_self_cert_test(self, ssl_app): + ssl_app.set_new_image(image_name=f"{IMAGE_NAME}-{ssl_app.app_name}") + assert ssl_app.create_container(cid_file_name=ssl_app.app_name, container_args="--user 1000") + cip = ssl_app.get_cip(cid_file_name=ssl_app.app_name) + assert cip + response = ".*" + assert ssl_app.test_response(url=f"{cip}", expected_code=200, expected_output=response) + assert ssl_app.test_response(url=f"https://{cip}", port=8443, expected_output="SSL test works") + server_cmd = f"openssl s_client -showcerts -servername {cip} -connect {cip}:8443 2>/dev/null" + server_output = ContainerTestLibUtils.run_command(cmd=server_cmd, return_output=True, debug=True) + print(f"server out from openssl command {server_output}") + certificate_dir = ContainerTestLibUtils.create_local_temp_dir("server_cert_dir") + with open(Path(certificate_dir) / "output", mode="wt+") as f: + f.write(server_output) + server_cert = ContainerTestLibUtils.run_command( + cmd=f"openssl x509 -inform pem -noout -text -in {Path(certificate_dir)}/output", + return_output=True, + debug=True + ) + config_cmd = f"openssl x509 -in {TEST_DIR}/{ssl_app.app_name}/httpd-ssl/certs/server-cert-selfsigned.pem -inform pem -noout -text" + config_cert = ContainerTestLibUtils.run_command(cmd=config_cmd, return_output=True) + assert server_cert == config_cert + + +class TestHttpdCertAgeContainer: + + def test_cert_age(self, s2i_sample_app): + assert s2i_sample_app.create_container(cid_file_name=s2i_sample_app.app_name, container_args="--user 1000") + image_age_s = PodmanCLIWrapper.podman_inspect( + field="{{.Created}}", src_image=IMAGE_NAME + ).strip().split(' ') + image_age = time.time() - float(ContainerTestLibUtils.run_command( + cmd=f"date -d '{image_age_s[0]} {image_age_s[1]} {image_age_s[2]}' '+%s'", return_output=True + )) + cid = s2i_sample_app.get_cid(s2i_sample_app.app_name) + certificate_content = PodmanCLIWrapper.podman_exec_bash_command( + cid_file_name=cid, cmd="cat \\$HTTPD_TLS_CERT_PATH/localhost.crt" + ).strip() + certificate_dir = ContainerTestLibUtils.create_local_temp_dir("cert_dir") + with open(Path(certificate_dir) / "cert", mode="w") as f: + f.write(certificate_content) + certificate_age_s = ContainerTestLibUtils.run_command( + cmd=f"openssl x509 -startdate -noout -in {Path(certificate_dir)}/cert", return_output=True + ).strip().replace("notBefore=", "") + certificate_age = time.time() - float(ContainerTestLibUtils.run_command( + cmd=f"date '+%s' --date='{certificate_age_s}'") + ) + assert certificate_age < image_age + assert PodmanCLIWrapper.podman_exec_bash_command( + cid_file_name=cid, cmd="ls -la \\$HTTPD_TLS_CERT_PATH/localhost.crt" + ) + assert PodmanCLIWrapper.podman_exec_bash_command( + cid_file_name=cid, cmd="ls -la \\$HTTPD_TLS_CERT_PATH/localhost.key" + ) From 884569aca5cc52a0e6971f78f15b91692a37ff49 Mon Sep 17 00:00:00 2001 From: "Petr \"Stone\" Hracek" Date: Mon, 22 Sep 2025 13:32:24 +0200 Subject: [PATCH 03/21] Rename test_httpd_* -> test_ocp_* Signed-off-by: Petr "Stone" Hracek --- .../{test_httpd_ex_template.py => test_ocp_ex_template.py} | 4 ++-- ...ttpd_imagestream_s2i.py => test_ocp_imagestream_s2i.py} | 0 ...test_httpd_imagestreams.py => test_ocp_imagestreams.py} | 0 .../{test_httpd_integration.py => test_ocp_integration.py} | 4 ++-- ...magestreams.py => test_ocp_shared_helm_imagestreams.py} | 0 ...d_helm_template.py => test_ocp_shared_helm_template.py} | 7 ++++++- 6 files changed, 10 insertions(+), 5 deletions(-) rename test/{test_httpd_ex_template.py => test_ocp_ex_template.py} (100%) rename test/{test_httpd_imagestream_s2i.py => test_ocp_imagestream_s2i.py} (100%) rename test/{test_httpd_imagestreams.py => test_ocp_imagestreams.py} (100%) rename test/{test_httpd_integration.py => test_ocp_integration.py} (98%) rename test/{test_httpd_shared_helm_imagestreams.py => test_ocp_shared_helm_imagestreams.py} (100%) rename test/{test_httpd_shared_helm_template.py => test_ocp_shared_helm_template.py} (90%) diff --git a/test/test_httpd_ex_template.py b/test/test_ocp_ex_template.py similarity index 100% rename from test/test_httpd_ex_template.py rename to test/test_ocp_ex_template.py index 5b0df2c1..555745c2 100644 --- a/test/test_httpd_ex_template.py +++ b/test/test_ocp_ex_template.py @@ -8,12 +8,12 @@ from container_ci_suite.openshift import OpenShiftAPI from container_ci_suite.utils import get_service_image, check_variables -TEST_DIR = Path(os.path.abspath(os.path.dirname(__file__))) - if not check_variables(): print("At least one variable from IMAGE_NAME, OS, VERSION is missing.") sys.exit(1) + +TEST_DIR = Path(os.path.abspath(os.path.dirname(__file__))) VERSION = os.getenv("VERSION") IMAGE_NAME = os.getenv("IMAGE_NAME") diff --git a/test/test_httpd_imagestream_s2i.py b/test/test_ocp_imagestream_s2i.py similarity index 100% rename from test/test_httpd_imagestream_s2i.py rename to test/test_ocp_imagestream_s2i.py diff --git a/test/test_httpd_imagestreams.py b/test/test_ocp_imagestreams.py similarity index 100% rename from test/test_httpd_imagestreams.py rename to test/test_ocp_imagestreams.py diff --git a/test/test_httpd_integration.py b/test/test_ocp_integration.py similarity index 98% rename from test/test_httpd_integration.py rename to test/test_ocp_integration.py index 0ad9efa1..c400cd96 100644 --- a/test/test_httpd_integration.py +++ b/test/test_ocp_integration.py @@ -1,15 +1,15 @@ import os import sys -import pytest - from container_ci_suite.openshift import OpenShiftAPI from container_ci_suite.utils import get_service_image, check_variables + if not check_variables(): print("At least one variable from IMAGE_NAME, OS, VERSION is missing.") sys.exit(1) + VERSION = os.getenv("VERSION") IMAGE_NAME = os.getenv("IMAGE_NAME") diff --git a/test/test_httpd_shared_helm_imagestreams.py b/test/test_ocp_shared_helm_imagestreams.py similarity index 100% rename from test/test_httpd_shared_helm_imagestreams.py rename to test/test_ocp_shared_helm_imagestreams.py diff --git a/test/test_httpd_shared_helm_template.py b/test/test_ocp_shared_helm_template.py similarity index 90% rename from test/test_httpd_shared_helm_template.py rename to test/test_ocp_shared_helm_template.py index 04e24a8a..8d7bda8f 100644 --- a/test/test_httpd_shared_helm_template.py +++ b/test/test_ocp_shared_helm_template.py @@ -1,13 +1,18 @@ import os +import sys -import pytest from pathlib import Path from container_ci_suite.helm import HelmChartsAPI +from container_ci_suite.utils import check_variables from constants import TAGS +if not check_variables(): + print("At least one variable from OS, VERSION is missing.") + sys.exit(1) + test_dir = Path(os.path.abspath(os.path.dirname(__file__))) VERSION = os.getenv("VERSION") From 00573a290b94a63091434b10623bc9b9966efdbd Mon Sep 17 00:00:00 2001 From: "Petr \"Stone\" Hracek" Date: Mon, 22 Sep 2025 13:32:51 +0200 Subject: [PATCH 04/21] Add tests to 2.4/test directory as symlinks Signed-off-by: Petr "Stone" Hracek --- 2.4/test/run-pytest | 1 + 2.4/test/test_container_httpd.py | 1 + 2.4/test/test_container_httpd_s2i.py | 1 + 2.4/test/test_container_ssl.py | 1 + 4 files changed, 4 insertions(+) create mode 120000 2.4/test/run-pytest create mode 120000 2.4/test/test_container_httpd.py create mode 120000 2.4/test/test_container_httpd_s2i.py create mode 120000 2.4/test/test_container_ssl.py diff --git a/2.4/test/run-pytest b/2.4/test/run-pytest new file mode 120000 index 00000000..efe32b48 --- /dev/null +++ b/2.4/test/run-pytest @@ -0,0 +1 @@ +../../test/run-pytest \ No newline at end of file diff --git a/2.4/test/test_container_httpd.py b/2.4/test/test_container_httpd.py new file mode 120000 index 00000000..1c002d86 --- /dev/null +++ b/2.4/test/test_container_httpd.py @@ -0,0 +1 @@ +../../test/test_container_httpd.py \ No newline at end of file diff --git a/2.4/test/test_container_httpd_s2i.py b/2.4/test/test_container_httpd_s2i.py new file mode 120000 index 00000000..6dbab8e8 --- /dev/null +++ b/2.4/test/test_container_httpd_s2i.py @@ -0,0 +1 @@ +../../test/test_container_httpd_s2i.py \ No newline at end of file diff --git a/2.4/test/test_container_ssl.py b/2.4/test/test_container_ssl.py new file mode 120000 index 00000000..4257c464 --- /dev/null +++ b/2.4/test/test_container_ssl.py @@ -0,0 +1 @@ +../../test/test_container_ssl.py \ No newline at end of file From ee7ccfd5c8c9e778f7fa4fa65f4c2bcad510b58f Mon Sep 17 00:00:00 2001 From: "Petr \"Stone\" Hracek" Date: Mon, 22 Sep 2025 13:38:36 +0200 Subject: [PATCH 05/21] Add symlinks to `2.4` and `2.4-micro` directory Signed-off-by: Petr "Stone" Hracek --- 2.4-micro/test/run-pytest | 1 + 2.4-micro/test/test_container_httpd.py | 1 + 2.4-micro/test/test_container_httpd_s2i.py | 1 + 2.4-micro/test/test_container_ssl.py | 1 + 2.4-micro/test/test_httpd_ex_template.py | 1 - 2.4-micro/test/test_httpd_imagestream_s2i.py | 1 - 2.4-micro/test/test_httpd_imagestreams.py | 1 - 2.4-micro/test/test_httpd_integration.py | 1 - 2.4-micro/test/test_httpd_shared_helm_imagestreams.py | 1 - 2.4-micro/test/test_httpd_shared_helm_template.py | 1 - 2.4-micro/test/test_ocp_ex_template.py | 1 + 2.4-micro/test/test_ocp_imagestream_s2i.py | 1 + 2.4-micro/test/test_ocp_imagestreams.py | 1 + 2.4-micro/test/test_ocp_integration.py | 1 + 2.4-micro/test/test_ocp_shared_helm_imagestreams.py | 1 + 2.4-micro/test/test_ocp_shared_helm_template.py | 1 + 2.4/test/test_httpd_ex_template.py | 1 - 2.4/test/test_httpd_imagestream_s2i.py | 1 - 2.4/test/test_httpd_imagestreams.py | 1 - 2.4/test/test_httpd_integration.py | 1 - 2.4/test/test_httpd_shared_helm_imagestreams.py | 1 - 2.4/test/test_httpd_shared_helm_template.py | 1 - 2.4/test/test_ocp_ex_template.py | 1 + 2.4/test/test_ocp_imagestream_s2i.py | 1 + 2.4/test/test_ocp_imagestreams.py | 1 + 2.4/test/test_ocp_integration.py | 1 + 2.4/test/test_ocp_shared_helm_imagestreams.py | 1 + 2.4/test/test_ocp_shared_helm_template.py | 1 + 28 files changed, 16 insertions(+), 12 deletions(-) create mode 120000 2.4-micro/test/run-pytest create mode 120000 2.4-micro/test/test_container_httpd.py create mode 120000 2.4-micro/test/test_container_httpd_s2i.py create mode 120000 2.4-micro/test/test_container_ssl.py delete mode 120000 2.4-micro/test/test_httpd_ex_template.py delete mode 120000 2.4-micro/test/test_httpd_imagestream_s2i.py delete mode 120000 2.4-micro/test/test_httpd_imagestreams.py delete mode 120000 2.4-micro/test/test_httpd_integration.py delete mode 120000 2.4-micro/test/test_httpd_shared_helm_imagestreams.py delete mode 120000 2.4-micro/test/test_httpd_shared_helm_template.py create mode 120000 2.4-micro/test/test_ocp_ex_template.py create mode 120000 2.4-micro/test/test_ocp_imagestream_s2i.py create mode 120000 2.4-micro/test/test_ocp_imagestreams.py create mode 120000 2.4-micro/test/test_ocp_integration.py create mode 120000 2.4-micro/test/test_ocp_shared_helm_imagestreams.py create mode 120000 2.4-micro/test/test_ocp_shared_helm_template.py delete mode 120000 2.4/test/test_httpd_ex_template.py delete mode 120000 2.4/test/test_httpd_imagestream_s2i.py delete mode 120000 2.4/test/test_httpd_imagestreams.py delete mode 120000 2.4/test/test_httpd_integration.py delete mode 120000 2.4/test/test_httpd_shared_helm_imagestreams.py delete mode 120000 2.4/test/test_httpd_shared_helm_template.py create mode 120000 2.4/test/test_ocp_ex_template.py create mode 120000 2.4/test/test_ocp_imagestream_s2i.py create mode 120000 2.4/test/test_ocp_imagestreams.py create mode 120000 2.4/test/test_ocp_integration.py create mode 120000 2.4/test/test_ocp_shared_helm_imagestreams.py create mode 120000 2.4/test/test_ocp_shared_helm_template.py diff --git a/2.4-micro/test/run-pytest b/2.4-micro/test/run-pytest new file mode 120000 index 00000000..efe32b48 --- /dev/null +++ b/2.4-micro/test/run-pytest @@ -0,0 +1 @@ +../../test/run-pytest \ No newline at end of file diff --git a/2.4-micro/test/test_container_httpd.py b/2.4-micro/test/test_container_httpd.py new file mode 120000 index 00000000..1c002d86 --- /dev/null +++ b/2.4-micro/test/test_container_httpd.py @@ -0,0 +1 @@ +../../test/test_container_httpd.py \ No newline at end of file diff --git a/2.4-micro/test/test_container_httpd_s2i.py b/2.4-micro/test/test_container_httpd_s2i.py new file mode 120000 index 00000000..6dbab8e8 --- /dev/null +++ b/2.4-micro/test/test_container_httpd_s2i.py @@ -0,0 +1 @@ +../../test/test_container_httpd_s2i.py \ No newline at end of file diff --git a/2.4-micro/test/test_container_ssl.py b/2.4-micro/test/test_container_ssl.py new file mode 120000 index 00000000..4257c464 --- /dev/null +++ b/2.4-micro/test/test_container_ssl.py @@ -0,0 +1 @@ +../../test/test_container_ssl.py \ No newline at end of file diff --git a/2.4-micro/test/test_httpd_ex_template.py b/2.4-micro/test/test_httpd_ex_template.py deleted file mode 120000 index 922da056..00000000 --- a/2.4-micro/test/test_httpd_ex_template.py +++ /dev/null @@ -1 +0,0 @@ -../../test/test_httpd_ex_template.py \ No newline at end of file diff --git a/2.4-micro/test/test_httpd_imagestream_s2i.py b/2.4-micro/test/test_httpd_imagestream_s2i.py deleted file mode 120000 index b24e3bab..00000000 --- a/2.4-micro/test/test_httpd_imagestream_s2i.py +++ /dev/null @@ -1 +0,0 @@ -../../test/test_httpd_imagestream_s2i.py \ No newline at end of file diff --git a/2.4-micro/test/test_httpd_imagestreams.py b/2.4-micro/test/test_httpd_imagestreams.py deleted file mode 120000 index c356f03a..00000000 --- a/2.4-micro/test/test_httpd_imagestreams.py +++ /dev/null @@ -1 +0,0 @@ -../../test/test_httpd_imagestreams.py \ No newline at end of file diff --git a/2.4-micro/test/test_httpd_integration.py b/2.4-micro/test/test_httpd_integration.py deleted file mode 120000 index 6634e2d6..00000000 --- a/2.4-micro/test/test_httpd_integration.py +++ /dev/null @@ -1 +0,0 @@ -../../test/test_httpd_integration.py \ No newline at end of file diff --git a/2.4-micro/test/test_httpd_shared_helm_imagestreams.py b/2.4-micro/test/test_httpd_shared_helm_imagestreams.py deleted file mode 120000 index 94930d9a..00000000 --- a/2.4-micro/test/test_httpd_shared_helm_imagestreams.py +++ /dev/null @@ -1 +0,0 @@ -../../test/test_httpd_shared_helm_imagestreams.py \ No newline at end of file diff --git a/2.4-micro/test/test_httpd_shared_helm_template.py b/2.4-micro/test/test_httpd_shared_helm_template.py deleted file mode 120000 index eec4d0a4..00000000 --- a/2.4-micro/test/test_httpd_shared_helm_template.py +++ /dev/null @@ -1 +0,0 @@ -../../test/test_httpd_shared_helm_template.py \ No newline at end of file diff --git a/2.4-micro/test/test_ocp_ex_template.py b/2.4-micro/test/test_ocp_ex_template.py new file mode 120000 index 00000000..002c0c4a --- /dev/null +++ b/2.4-micro/test/test_ocp_ex_template.py @@ -0,0 +1 @@ +../../test/test_ocp_ex_template.py \ No newline at end of file diff --git a/2.4-micro/test/test_ocp_imagestream_s2i.py b/2.4-micro/test/test_ocp_imagestream_s2i.py new file mode 120000 index 00000000..89eb6791 --- /dev/null +++ b/2.4-micro/test/test_ocp_imagestream_s2i.py @@ -0,0 +1 @@ +../../test/test_ocp_imagestream_s2i.py \ No newline at end of file diff --git a/2.4-micro/test/test_ocp_imagestreams.py b/2.4-micro/test/test_ocp_imagestreams.py new file mode 120000 index 00000000..ee905e77 --- /dev/null +++ b/2.4-micro/test/test_ocp_imagestreams.py @@ -0,0 +1 @@ +../../test/test_ocp_imagestreams.py \ No newline at end of file diff --git a/2.4-micro/test/test_ocp_integration.py b/2.4-micro/test/test_ocp_integration.py new file mode 120000 index 00000000..12a7b4f0 --- /dev/null +++ b/2.4-micro/test/test_ocp_integration.py @@ -0,0 +1 @@ +../../test/test_ocp_integration.py \ No newline at end of file diff --git a/2.4-micro/test/test_ocp_shared_helm_imagestreams.py b/2.4-micro/test/test_ocp_shared_helm_imagestreams.py new file mode 120000 index 00000000..76d5701d --- /dev/null +++ b/2.4-micro/test/test_ocp_shared_helm_imagestreams.py @@ -0,0 +1 @@ +../../test/test_ocp_shared_helm_imagestreams.py \ No newline at end of file diff --git a/2.4-micro/test/test_ocp_shared_helm_template.py b/2.4-micro/test/test_ocp_shared_helm_template.py new file mode 120000 index 00000000..9cf469bf --- /dev/null +++ b/2.4-micro/test/test_ocp_shared_helm_template.py @@ -0,0 +1 @@ +../../test/test_ocp_shared_helm_template.py \ No newline at end of file diff --git a/2.4/test/test_httpd_ex_template.py b/2.4/test/test_httpd_ex_template.py deleted file mode 120000 index 922da056..00000000 --- a/2.4/test/test_httpd_ex_template.py +++ /dev/null @@ -1 +0,0 @@ -../../test/test_httpd_ex_template.py \ No newline at end of file diff --git a/2.4/test/test_httpd_imagestream_s2i.py b/2.4/test/test_httpd_imagestream_s2i.py deleted file mode 120000 index b24e3bab..00000000 --- a/2.4/test/test_httpd_imagestream_s2i.py +++ /dev/null @@ -1 +0,0 @@ -../../test/test_httpd_imagestream_s2i.py \ No newline at end of file diff --git a/2.4/test/test_httpd_imagestreams.py b/2.4/test/test_httpd_imagestreams.py deleted file mode 120000 index c356f03a..00000000 --- a/2.4/test/test_httpd_imagestreams.py +++ /dev/null @@ -1 +0,0 @@ -../../test/test_httpd_imagestreams.py \ No newline at end of file diff --git a/2.4/test/test_httpd_integration.py b/2.4/test/test_httpd_integration.py deleted file mode 120000 index 6634e2d6..00000000 --- a/2.4/test/test_httpd_integration.py +++ /dev/null @@ -1 +0,0 @@ -../../test/test_httpd_integration.py \ No newline at end of file diff --git a/2.4/test/test_httpd_shared_helm_imagestreams.py b/2.4/test/test_httpd_shared_helm_imagestreams.py deleted file mode 120000 index 94930d9a..00000000 --- a/2.4/test/test_httpd_shared_helm_imagestreams.py +++ /dev/null @@ -1 +0,0 @@ -../../test/test_httpd_shared_helm_imagestreams.py \ No newline at end of file diff --git a/2.4/test/test_httpd_shared_helm_template.py b/2.4/test/test_httpd_shared_helm_template.py deleted file mode 120000 index eec4d0a4..00000000 --- a/2.4/test/test_httpd_shared_helm_template.py +++ /dev/null @@ -1 +0,0 @@ -../../test/test_httpd_shared_helm_template.py \ No newline at end of file diff --git a/2.4/test/test_ocp_ex_template.py b/2.4/test/test_ocp_ex_template.py new file mode 120000 index 00000000..002c0c4a --- /dev/null +++ b/2.4/test/test_ocp_ex_template.py @@ -0,0 +1 @@ +../../test/test_ocp_ex_template.py \ No newline at end of file diff --git a/2.4/test/test_ocp_imagestream_s2i.py b/2.4/test/test_ocp_imagestream_s2i.py new file mode 120000 index 00000000..89eb6791 --- /dev/null +++ b/2.4/test/test_ocp_imagestream_s2i.py @@ -0,0 +1 @@ +../../test/test_ocp_imagestream_s2i.py \ No newline at end of file diff --git a/2.4/test/test_ocp_imagestreams.py b/2.4/test/test_ocp_imagestreams.py new file mode 120000 index 00000000..ee905e77 --- /dev/null +++ b/2.4/test/test_ocp_imagestreams.py @@ -0,0 +1 @@ +../../test/test_ocp_imagestreams.py \ No newline at end of file diff --git a/2.4/test/test_ocp_integration.py b/2.4/test/test_ocp_integration.py new file mode 120000 index 00000000..12a7b4f0 --- /dev/null +++ b/2.4/test/test_ocp_integration.py @@ -0,0 +1 @@ +../../test/test_ocp_integration.py \ No newline at end of file diff --git a/2.4/test/test_ocp_shared_helm_imagestreams.py b/2.4/test/test_ocp_shared_helm_imagestreams.py new file mode 120000 index 00000000..76d5701d --- /dev/null +++ b/2.4/test/test_ocp_shared_helm_imagestreams.py @@ -0,0 +1 @@ +../../test/test_ocp_shared_helm_imagestreams.py \ No newline at end of file diff --git a/2.4/test/test_ocp_shared_helm_template.py b/2.4/test/test_ocp_shared_helm_template.py new file mode 120000 index 00000000..9cf469bf --- /dev/null +++ b/2.4/test/test_ocp_shared_helm_template.py @@ -0,0 +1 @@ +../../test/test_ocp_shared_helm_template.py \ No newline at end of file From ea65bf9c2481dc319078826fb0a0721fd2b18ca9 Mon Sep 17 00:00:00 2001 From: "Petr \"Stone\" Hracek" Date: Mon, 22 Sep 2025 14:14:28 +0200 Subject: [PATCH 06/21] Add missing function to `constants.py` Signed-off-by: Petr "Stone" Hracek --- test/constants.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/constants.py b/test/constants.py index e0402ba6..bdf49b21 100644 --- a/test/constants.py +++ b/test/constants.py @@ -1,5 +1,11 @@ +import os + + TAGS = { "rhel8": "-ubi8", "rhel9": "-ubi9", "rhel10": "-ubi10", } + +def return_app_name(request): + return os.path.basename(request.param) From b1e158eb24ee09831551692cc757700dba4d5a31 Mon Sep 17 00:00:00 2001 From: Petr Hracek Date: Tue, 23 Sep 2025 13:41:58 +0200 Subject: [PATCH 07/21] Removing leftovers Co-authored-by: Karolina Surma <33810531+befeleme@users.noreply.github.com> --- test/test_container_httpd_s2i.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/test_container_httpd_s2i.py b/test/test_container_httpd_s2i.py index 5c21d92d..83e91747 100644 --- a/test/test_container_httpd_s2i.py +++ b/test/test_container_httpd_s2i.py @@ -24,8 +24,6 @@ print(f"Built container for version {VERSION} on OS {OS} does not exist.") sys.exit(1) -image_tag_wo_tag = IMAGE_NAME.split(":")[0] -image_tag = IMAGE_NAME.split(":")[1] pre_init_test_app = os.path.join(TEST_DIR, "pre-init-test-app") sample_test_app = os.path.join(TEST_DIR, "sample-test-app") From 3ea9aed38b74073b105ae70d8b740eaf9d7a90e4 Mon Sep 17 00:00:00 2001 From: Petr Hracek Date: Tue, 23 Sep 2025 13:42:13 +0200 Subject: [PATCH 08/21] Remove leftovers Co-authored-by: Karolina Surma <33810531+befeleme@users.noreply.github.com> --- test/test_container_ssl.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/test_container_ssl.py b/test/test_container_ssl.py index 0038779c..c08e7101 100644 --- a/test/test_container_ssl.py +++ b/test/test_container_ssl.py @@ -23,8 +23,6 @@ print(f"Built container for version {VERSION} on OS {OS} does not exist.") sys.exit(1) -image_tag_wo_tag = IMAGE_NAME.split(":")[0] -image_tag = IMAGE_NAME.split(":")[1] self_cert_test = os.path.join(TEST_DIR, "self-signed-ssl") sample_test_app = os.path.join(TEST_DIR, "sample-test-app") From 1b6e27dd8c9ab7800c34703a62ef2b25a6f56808 Mon Sep 17 00:00:00 2001 From: Petr Hracek Date: Tue, 23 Sep 2025 13:43:30 +0200 Subject: [PATCH 09/21] Remove leftovers. Co-authored-by: Karolina Surma <33810531+befeleme@users.noreply.github.com> --- test/test_container_ssl.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/test/test_container_ssl.py b/test/test_container_ssl.py index c08e7101..71a2d966 100644 --- a/test/test_container_ssl.py +++ b/test/test_container_ssl.py @@ -52,12 +52,6 @@ def ssl_app(request): yield s2i_app s2i_app.clean_containers() -@pytest.fixture(scope="module") -def app(request): - app = ContainerTestLib(image_name=IMAGE_NAME, s2i_image=True) - yield app - app.clean_containers() - app.clean_app_images() class TestHttpdS2ISslSelfSignedAppContainer: From db4b4668b151199df9acf3e70db6d1a51364ae88 Mon Sep 17 00:00:00 2001 From: Petr Hracek Date: Tue, 23 Sep 2025 16:03:00 +0200 Subject: [PATCH 10/21] app is not parametrized MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Lumír 'Frenzy' Balhar --- test/test_container_httpd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_container_httpd.py b/test/test_container_httpd.py index f95aaec6..9dcfe79c 100644 --- a/test/test_container_httpd.py +++ b/test/test_container_httpd.py @@ -25,7 +25,7 @@ @pytest.fixture(scope="module") -def app(request): +def app(): app = ContainerTestLib(image_name=IMAGE_NAME, s2i_image=True) yield app app.clean_containers() From 0ad18a850ac9c5d8f111596984376f53ea03b862 Mon Sep 17 00:00:00 2001 From: Petr Hracek Date: Tue, 23 Sep 2025 16:03:46 +0200 Subject: [PATCH 11/21] assert output and not check empty string. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Lumír 'Frenzy' Balhar --- test/test_container_httpd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_container_httpd.py b/test/test_container_httpd.py index 9dcfe79c..1c04eb7c 100644 --- a/test/test_container_httpd.py +++ b/test/test_container_httpd.py @@ -58,7 +58,7 @@ def test_run_as_root(self, app): def test_run_s2i_usage(self, app): output = app.s2i_usage() print(f"S2i_USAGE output: '{output}'") - assert output != "" + assert output @pytest.mark.parametrize( "dockerfile", From 83e280e4ad05d99bc427b91786ec820360bf69e5 Mon Sep 17 00:00:00 2001 From: "Petr \"Stone\" Hracek" Date: Wed, 24 Sep 2025 15:19:35 +0200 Subject: [PATCH 12/21] Remove function from constants.py. Remove fixtures. They are not needed. Signed-off-by: Petr "Stone" Hracek --- test/constants.py | 6 -- test/run-pytest | 2 +- test/test_container_httpd.py | 125 ++++++++++------------- test/test_container_httpd_s2i.py | 164 ++++++++++++++++++++----------- test/test_container_ssl.py | 121 +++++++---------------- 5 files changed, 193 insertions(+), 225 deletions(-) diff --git a/test/constants.py b/test/constants.py index bdf49b21..e0402ba6 100644 --- a/test/constants.py +++ b/test/constants.py @@ -1,11 +1,5 @@ -import os - - TAGS = { "rhel8": "-ubi8", "rhel9": "-ubi9", "rhel10": "-ubi10", } - -def return_app_name(request): - return os.path.basename(request.param) diff --git a/test/run-pytest b/test/run-pytest index e69959ad..35fca679 100755 --- a/test/run-pytest +++ b/test/run-pytest @@ -2,7 +2,7 @@ # # IMAGE_NAME specifies a name of the candidate image used for testing. # The image has to be available before this script is executed. -# SINGLE_VERSION specifies the major version of the MariaDB in format of X.Y +# SINGLE_VERSION specifies the major version of httpd # OS specifies RHEL version (e.g. OS=rhel8) # diff --git a/test/test_container_httpd.py b/test/test_container_httpd.py index 1c04eb7c..5c355f98 100644 --- a/test/test_container_httpd.py +++ b/test/test_container_httpd.py @@ -1,63 +1,45 @@ import os -import sys - -import pytest +import re +import tempfile from pathlib import Path -from container_ci_suite.container_lib import ContainerTestLib -from container_ci_suite.utils import check_variables, ContainerTestLibUtils - +import pytest -if not check_variables(): - print("At least one variable from OS, VERSION is missing.") - sys.exit(1) +from container_ci_suite.container_lib import ContainerTestLib +from container_ci_suite.utils import ContainerTestLibUtils -TEST_DIR = Path(os.path.abspath(os.path.dirname(__file__))) +TEST_DIR = Path(__file__).parent.absolute() VERSION = os.getenv("VERSION") -OS = os.getenv("OS") +OS = os.getenv("OS").lower() IMAGE_NAME = os.getenv("IMAGE_NAME") -if not IMAGE_NAME: - print(f"Built container for version {VERSION} on OS {OS} does not exist.") - sys.exit(1) -print(f"Test dir is: {TEST_DIR}") -@pytest.fixture(scope="module") -def app(): - app = ContainerTestLib(image_name=IMAGE_NAME, s2i_image=True) - yield app - app.clean_containers() - app.clean_app_images() +class TestHttpdAppContainer: + def setup_method(self): + self.app = ContainerTestLib(image_name=IMAGE_NAME, s2i_image=True) -class TestHttpdAppContainer: + def teardown_method(self): + self.app.cleanup() - def test_default_page(self, app): - assert app.create_container(cid_file_name="test_default_page") - cip = app.get_cip("test_default_page") - assert cip - if OS == "c9s" or OS == "c10s": - response = "HTTP Server Test Page" - else: - # The RHEL and Fedora OS gets this response - response = "Test Page for the HTTP Server on" - assert app.test_response(url=f"{cip}", expected_code=403, expected_output=response, max_attempts=3) - - def test_run_as_root(self, app): - assert app.create_container(cid_file_name="test_default_page", container_args="--user 0") - cip = app.get_cip("test_default_page") + @pytest.mark.parametrize( + "container_arg", + [ + "", + "--user 0" + ] + ) + def test_default_page(self, container_arg): + assert self.app.create_container(cid_file_name="test_default_page", container_args=container_arg) + cip = self.app.get_cip("test_default_page") assert cip - if OS == "c9s" or OS == "c10s": - response = "HTTP Server Test Page" - else: - response = "Test Page for the HTTP Server on" - assert app.test_response(url=f"{cip}", expected_code=403, expected_output=response, max_attempts=3) - - def test_run_s2i_usage(self, app): - output = app.s2i_usage() - print(f"S2i_USAGE output: '{output}'") + response = "HTTP Server" + assert self.app.test_response(url=cip, expected_code=403, expected_output=response, max_attempts=3) + + def test_run_s2i_usage(self): + output = self.app.s2i_usage() assert output @pytest.mark.parametrize( @@ -67,15 +49,15 @@ def test_run_s2i_usage(self, app): "Dockerfile.s2i" ] ) - def test_dockerfiles(self, app, dockerfile): - assert app.build_test_container( - dockerfile=f"{TEST_DIR}/examples/{dockerfile}", app_url="https://github.com/sclorg/httpd-ex.git", + def test_dockerfiles(self, dockerfile): + assert self.app.build_test_container( + dockerfile=TEST_DIR / "examples" / dockerfile, app_url="https://github.com/sclorg/httpd-ex.git", app_dir="app-src" ) - assert app.test_app_dockerfile() - cip = app.get_cip() + assert self.app.test_app_dockerfile() + cip = self.app.get_cip() assert cip - assert app.test_response(url=f"{cip}", expected_code=200, expected_output="Welcome to your static httpd application on OpenShift") + assert self.app.test_response(url=f"{cip}", expected_code=200, expected_output="Welcome to your static httpd application on OpenShift") @pytest.mark.parametrize( "mpm_config", @@ -85,23 +67,20 @@ def test_dockerfiles(self, app, dockerfile): "prefork", ] ) - def test_mpm_config(self, app, mpm_config): + def test_mpm_config(self, mpm_config): cid_name = f"test_mpm_{mpm_config}" - assert app.create_container(cid_file_name=cid_name, container_args=f"-e HTTPD_MPM={mpm_config} --user 1001") - cip = app.get_cip(cid_file_name=cid_name) + assert self.app.create_container(cid_file_name=cid_name, container_args=f"-e HTTPD_MPM={mpm_config} --user 1001") + cip = self.app.get_cip(cid_file_name=cid_name) # Let's check that server really response HTTP-403 # See function here: in test/run `_run_mpm_config_test` # https://github.com/sclorg/httpd-container/blob/master/test/run#L97 - assert app.test_response(url=f"{cip}", port=8080, expected_code=403, expected_output=".*" ) - logs = app.get_logs(cid_file_name=cid_name) - assert ContainerTestLibUtils.check_regexp_output( - regexp_to_check=f"mpm_{mpm_config}:notice.*resuming normal operations", - logs_to_check=logs - ) - def test_log_to_data_volume(self, app): - data_dir = ContainerTestLibUtils.create_local_temp_dir( - dir_name="/tmp/httpd-test_log_dir" - ) + assert self.app.test_response(url=f"{cip}", port=8080, expected_code=403) + logs = self.app.get_logs(cid_file_name=cid_name) + assert re.search(f"mpm_{mpm_config}:notice.*resuming normal operations", logs) + + + def test_log_to_data_volume(self): + data_dir = tempfile.mkdtemp(prefix="/tmp/httpd-test_log_dir") ContainerTestLibUtils.commands_to_run( commands_to_run = [ f"mkdir -p {data_dir}", @@ -109,12 +88,12 @@ def test_log_to_data_volume(self, app): f"chcon -Rvt svirt_sandbox_file_t {data_dir}/" ] ) - assert app.create_container( + assert self.app.create_container( cid_file_name="test_log_dir", container_args=f"-e HTTPD_LOG_TO_VOLUME=1 --user 0 -v {data_dir}:/var/log/httpd" ) - cip = app.get_cip(cid_file_name="test_log_dir") - assert app.test_response(url=f"{cip}", port=8080, expected_code=403, expected_output=".*") + cip = self.app.get_cip(cid_file_name="test_log_dir") + assert self.app.test_response(url=f"{cip}", port=8080, expected_code=403) assert ContainerTestLibUtils.check_files_are_present( dir_name=data_dir, file_name_to_check=[ "access_log", @@ -125,10 +104,8 @@ def test_log_to_data_volume(self, app): ] ) - def test_data_volume(self, app): - data_dir = ContainerTestLibUtils.create_local_temp_dir( - dir_name="/tmp/httpd-test-volume" - ) + def test_data_volume(self): + data_dir = tempfile.mkdtemp(prefix="/tmp/httpd-test-volume") ContainerTestLibUtils.commands_to_run( commands_to_run = [ f"mkdir -p {data_dir}/html", @@ -137,10 +114,10 @@ def test_data_volume(self, app): f"chcon -Rvt svirt_sandbox_file_t {data_dir}/" ] ) - assert app.create_container( + assert self.app.create_container( cid_file_name="doc_root", container_args=f"-v {data_dir}:/var/www" ) - cip = app.get_cip(cid_file_name="doc_root") + cip = self.app.get_cip(cid_file_name="doc_root") assert cip - assert app.test_response(url=f"{cip}", port=8080, expected_code=200, expected_output="hello") + assert self.app.test_response(url=f"{cip}", port=8080, expected_code=200, expected_output="hello") diff --git a/test/test_container_httpd_s2i.py b/test/test_container_httpd_s2i.py index 83e91747..39e24633 100644 --- a/test/test_container_httpd_s2i.py +++ b/test/test_container_httpd_s2i.py @@ -1,82 +1,134 @@ import os -import sys -import pytest +import time +import tempfile from pathlib import Path from container_ci_suite.container_lib import ContainerTestLib -from container_ci_suite.utils import check_variables +from container_ci_suite.utils import ContainerTestLibUtils +from container_ci_suite.engines.podman_wrapper import PodmanCLIWrapper -from constants import return_app_name - - -if not check_variables(): - print("At least one variable from OS, VERSION is missing.") - sys.exit(1) - - -TEST_DIR = Path(os.path.abspath(os.path.dirname(__file__))) +TEST_DIR = Path(__file__).parent.absolute() VERSION = os.getenv("VERSION") OS = os.getenv("TARGET") IMAGE_NAME = os.getenv("IMAGE_NAME") -if not IMAGE_NAME: - print(f"Built container for version {VERSION} on OS {OS} does not exist.") - sys.exit(1) - -pre_init_test_app = os.path.join(TEST_DIR, "pre-init-test-app") -sample_test_app = os.path.join(TEST_DIR, "sample-test-app") - - -@pytest.fixture(scope="module", params=[pre_init_test_app]) -def s2i_app_pre_init(request): - container_lib = ContainerTestLib(IMAGE_NAME) - app_name = return_app_name(request) - s2i_app = container_lib.build_as_df( - app_path=request.param, - s2i_args="--pull-policy=never", - src_image=IMAGE_NAME, - dst_image=f"{IMAGE_NAME}-{app_name}" - ) - yield s2i_app - s2i_app.clean_containers() - - -@pytest.fixture(scope="module", params=[sample_test_app]) -def s2i_sample_app(request): - ci = ContainerTestLib(IMAGE_NAME) - app_name = return_app_name(request) - s2i_app = ci.build_as_df( - app_path=request.param, - s2i_args="--pull-policy=never", - src_image=IMAGE_NAME, - dst_image=f"{IMAGE_NAME}-{app_name}" - ) - yield s2i_app - s2i_app.clean_containers() + + +pre_init_test_app = TEST_DIR / "pre-init-test-app" +sample_test_app = TEST_DIR / "sample-test-app" class TestHttpdS2IPreInitContainer: - def test_run_pre_init_test(self, s2i_app_pre_init): - assert s2i_app_pre_init.create_container(cid_file_name=s2i_app_pre_init.app_name, container_args="--user 1000") - cip = s2i_app_pre_init.get_cip(cid_file_name=s2i_app_pre_init.app_name) + def setup_method(self): + self.container_lib = ContainerTestLib(IMAGE_NAME) + print(self.container_lib) + app_name = pre_init_test_app.name + print(app_name) + self.s2i_app = self.container_lib.build_as_df( + app_path=pre_init_test_app, + s2i_args="--pull-policy=never", + src_image=IMAGE_NAME, + dst_image=f"{IMAGE_NAME}-{app_name}" + ) + + def teardown_method(self): + self.s2i_app.cleanup() + + def test_run_pre_init_test(self): + assert self.s2i_app.create_container(cid_file_name=self.s2i_app.app_name, container_args="--user 1000") + cip = self.s2i_app.get_cip(cid_file_name=self.s2i_app.app_name) assert cip - response = f"This content was replaced by pre-init script." - assert s2i_app_pre_init.test_response(url=f"{cip}", expected_code=200, expected_output=response) + assert self.s2i_app.test_response( + url=cip, + expected_code=200, + expected_output="This content was replaced by pre-init script." + ) class TestHttpdS2ISampleAppContainer: - def test_sample_app(self, s2i_sample_app): - assert s2i_sample_app.create_container(cid_file_name=s2i_sample_app.app_name, container_args="--user 1000") - cip = s2i_sample_app.get_cip(cid_file_name=s2i_sample_app.app_name) + def setup_method(self): + self.ci = ContainerTestLib(IMAGE_NAME) + app_name = sample_test_app.name + self.s2i_app = self.ci.build_as_df( + app_path=sample_test_app, + s2i_args="--pull-policy=never", + src_image=IMAGE_NAME, + dst_image=f"{IMAGE_NAME}-{app_name}" + ) + + def teardown_method(self): + self.s2i_app.cleanup() + + def test_sample_app(self): + assert self.s2i_app.create_container(cid_file_name=self.s2i_app.app_name, container_args="--user 1000") + cip = self.s2i_app.get_cip(cid_file_name=self.s2i_app.app_name) assert cip response = "This is a sample s2i application with static content." - assert s2i_sample_app.test_response(url=f"{cip}", expected_code=200, expected_output=response) - assert s2i_sample_app.test_response( + assert self.s2i_app.test_response( + url=cip, + expected_code=200, + expected_output=response + ) + assert self.s2i_app.test_response( url=f"https://{cip}", port=8443, expected_output=response ) + +class TestHttpdCertAgeContainer: + + def setup_method(self): + self.ci = ContainerTestLib(IMAGE_NAME) + app_name = sample_test_app.name + self.s2i_app = self.ci.build_as_df( + app_path=sample_test_app, + s2i_args="--pull-policy=never", + src_image=IMAGE_NAME, + dst_image=f"{IMAGE_NAME}-{app_name}" + ) + + def teardown_method(self): + self.s2i_app.cleanup() + + """ + This tests checks whether the certificate was freshly generated after the image + We need to make sure the certificate is generated no sooner than in assemble phase, + because shipping the same certs in the image would make it easy to exploit + Let's see how old the certificate is and compare with how old the image is + """ + def test_cert_age(self): + assert self.s2i_app.create_container(cid_file_name=self.s2i_app.app_name, container_args="--user 1000") + image_age_s = PodmanCLIWrapper.podman_inspect( + field="{{.Created}}", src_image=IMAGE_NAME + ).strip().split(' ') + image_age = time.time() - float(ContainerTestLibUtils.run_command( + cmd=f"date -d '{image_age_s[0]} {image_age_s[1]} {image_age_s[2]}' '+%s'" + )) + cid = self.s2i_app.get_cid(self.s2i_app.app_name) + # Testing of not presence of a certificate in the production image + certificate_content = PodmanCLIWrapper.podman_exec_bash_command( + cid_file_name=cid, cmd="cat \\$HTTPD_TLS_CERT_PATH/localhost.crt" + ).strip() + certificate_dir = tempfile.mkdtemp(prefix="/tmp/cert_dir") + with open(Path(certificate_dir) / "cert", mode="w") as f: + f.write(certificate_content) + certificate_age_s = ContainerTestLibUtils.run_command( + cmd=f"openssl x509 -startdate -noout -in {Path(certificate_dir)}/cert" + ).strip().replace("notBefore=", "") + certificate_age = time.time() - float(ContainerTestLibUtils.run_command( + cmd=f"date '+%s' --date='{certificate_age_s}'") + ) + # Testing whether the certificate was freshly generated after the image + assert certificate_age < image_age + # Testing presence and permissions of the generated certificate + assert PodmanCLIWrapper.podman_exec_bash_command( + cid_file_name=cid, cmd="ls -l \\$HTTPD_TLS_CERT_PATH/localhost.crt" + ) + # Testing presence and permissions of the generated certificate + assert PodmanCLIWrapper.podman_exec_bash_command( + cid_file_name=cid, cmd="ls -l \\$HTTPD_TLS_CERT_PATH/localhost.key" + ) diff --git a/test/test_container_ssl.py b/test/test_container_ssl.py index 71a2d966..6b513b9c 100644 --- a/test/test_container_ssl.py +++ b/test/test_container_ssl.py @@ -1,112 +1,57 @@ import os -import sys -import pytest -import time +import tempfile from pathlib import Path from container_ci_suite.container_lib import ContainerTestLib -from container_ci_suite.utils import check_variables, ContainerTestLibUtils -from container_ci_suite.engines.podman_wrapper import PodmanCLIWrapper +from container_ci_suite.utils import ContainerTestLibUtils -if not check_variables(): - print("At least one variable from OS, VERSION is missing.") - sys.exit(1) - - -TEST_DIR = Path(os.path.abspath(os.path.dirname(__file__))) +TEST_DIR = Path(__file__).parent.absolute() VERSION = os.getenv("VERSION") OS = os.getenv("TARGET") IMAGE_NAME = os.getenv("IMAGE_NAME") -if not IMAGE_NAME: - print(f"Built container for version {VERSION} on OS {OS} does not exist.") - sys.exit(1) - -self_cert_test = os.path.join(TEST_DIR, "self-signed-ssl") -sample_test_app = os.path.join(TEST_DIR, "sample-test-app") -@pytest.fixture(scope="module", params=[sample_test_app]) -def s2i_sample_app(request): - ci = ContainerTestLib(IMAGE_NAME) - app_name = os.path.basename(request.param) - s2i_app = ci.build_as_df( - app_path=request.param, - s2i_args="--pull-policy=never", - src_image=IMAGE_NAME, - dst_image=f"{IMAGE_NAME}-{app_name}" - ) - yield s2i_app - s2i_app.clean_containers() - -@pytest.fixture(scope="module", params=[self_cert_test]) -def ssl_app(request): - ci = ContainerTestLib(IMAGE_NAME) - app_name = os.path.basename(request.param) - s2i_app = ci.build_as_df( - app_path=request.param, - s2i_args="--pull-policy=never", - src_image=IMAGE_NAME, - dst_image=f"{IMAGE_NAME}-{app_name}" - ) - yield s2i_app - s2i_app.clean_containers() +self_cert_test = TEST_DIR / "self-signed-ssl" class TestHttpdS2ISslSelfSignedAppContainer: - def test_self_cert_test(self, ssl_app): - ssl_app.set_new_image(image_name=f"{IMAGE_NAME}-{ssl_app.app_name}") - assert ssl_app.create_container(cid_file_name=ssl_app.app_name, container_args="--user 1000") - cip = ssl_app.get_cip(cid_file_name=ssl_app.app_name) + def setup_method(self): + self.ci = ContainerTestLib(IMAGE_NAME) + app_name = self_cert_test.name + self.s2i_app = self.ci.build_as_df( + app_path=self_cert_test, + s2i_args="--pull-policy=never", + src_image=IMAGE_NAME, + dst_image=f"{IMAGE_NAME}-{app_name}" + ) + + def teardown_method(self): + self.s2i_app.cleanup() + + """ + Test s2i use case #3 - using own ssl certs + Since we built the candidate image locally, we don't want S2I attempt to pull + it from Docker hub + """ + def test_self_cert_test(self): + self.s2i_app.set_new_image(image_name=f"{IMAGE_NAME}-{self.s2i_app.app_name}") + assert self.s2i_app.create_container(cid_file_name=self.s2i_app.app_name, container_args="--user 1000") + cip = self.s2i_app.get_cip(cid_file_name=self.s2i_app.app_name) assert cip response = ".*" - assert ssl_app.test_response(url=f"{cip}", expected_code=200, expected_output=response) - assert ssl_app.test_response(url=f"https://{cip}", port=8443, expected_output="SSL test works") + assert self.s2i_app.test_response(url=f"{cip}", expected_code=200, expected_output=response) + assert self.s2i_app.test_response(url=f"https://{cip}", port=8443, expected_output="SSL test works") server_cmd = f"openssl s_client -showcerts -servername {cip} -connect {cip}:8443 2>/dev/null" - server_output = ContainerTestLibUtils.run_command(cmd=server_cmd, return_output=True, debug=True) - print(f"server out from openssl command {server_output}") - certificate_dir = ContainerTestLibUtils.create_local_temp_dir("server_cert_dir") + server_output = ContainerTestLibUtils.run_command(cmd=server_cmd) + certificate_dir = tempfile.mkdtemp(prefix="/tmp/server_cert_dir") with open(Path(certificate_dir) / "output", mode="wt+") as f: f.write(server_output) server_cert = ContainerTestLibUtils.run_command( - cmd=f"openssl x509 -inform pem -noout -text -in {Path(certificate_dir)}/output", - return_output=True, - debug=True + cmd=f"openssl x509 -inform pem -noout -text -in {Path(certificate_dir)}/output" ) - config_cmd = f"openssl x509 -in {TEST_DIR}/{ssl_app.app_name}/httpd-ssl/certs/server-cert-selfsigned.pem -inform pem -noout -text" - config_cert = ContainerTestLibUtils.run_command(cmd=config_cmd, return_output=True) + config_cmd = f"openssl x509 -in {TEST_DIR}/{self.s2i_app.app_name}/httpd-ssl/certs/server-cert-selfsigned.pem -inform pem -noout -text" + config_cert = ContainerTestLibUtils.run_command(cmd=config_cmd) assert server_cert == config_cert - - -class TestHttpdCertAgeContainer: - - def test_cert_age(self, s2i_sample_app): - assert s2i_sample_app.create_container(cid_file_name=s2i_sample_app.app_name, container_args="--user 1000") - image_age_s = PodmanCLIWrapper.podman_inspect( - field="{{.Created}}", src_image=IMAGE_NAME - ).strip().split(' ') - image_age = time.time() - float(ContainerTestLibUtils.run_command( - cmd=f"date -d '{image_age_s[0]} {image_age_s[1]} {image_age_s[2]}' '+%s'", return_output=True - )) - cid = s2i_sample_app.get_cid(s2i_sample_app.app_name) - certificate_content = PodmanCLIWrapper.podman_exec_bash_command( - cid_file_name=cid, cmd="cat \\$HTTPD_TLS_CERT_PATH/localhost.crt" - ).strip() - certificate_dir = ContainerTestLibUtils.create_local_temp_dir("cert_dir") - with open(Path(certificate_dir) / "cert", mode="w") as f: - f.write(certificate_content) - certificate_age_s = ContainerTestLibUtils.run_command( - cmd=f"openssl x509 -startdate -noout -in {Path(certificate_dir)}/cert", return_output=True - ).strip().replace("notBefore=", "") - certificate_age = time.time() - float(ContainerTestLibUtils.run_command( - cmd=f"date '+%s' --date='{certificate_age_s}'") - ) - assert certificate_age < image_age - assert PodmanCLIWrapper.podman_exec_bash_command( - cid_file_name=cid, cmd="ls -la \\$HTTPD_TLS_CERT_PATH/localhost.crt" - ) - assert PodmanCLIWrapper.podman_exec_bash_command( - cid_file_name=cid, cmd="ls -la \\$HTTPD_TLS_CERT_PATH/localhost.key" - ) From 8862757a6f1ad4c9ee8489e3c8bad949bfd23b94 Mon Sep 17 00:00:00 2001 From: "Petr \"Stone\" Hracek" Date: Thu, 25 Sep 2025 11:03:15 +0200 Subject: [PATCH 13/21] Update tests suite and use new shell command. In case of podman exec failed, then return is False instead of silence failure Signed-off-by: Petr "Stone" Hracek --- test/test_container_httpd_s2i.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/test/test_container_httpd_s2i.py b/test/test_container_httpd_s2i.py index 39e24633..a14487b9 100644 --- a/test/test_container_httpd_s2i.py +++ b/test/test_container_httpd_s2i.py @@ -110,12 +110,13 @@ def test_cert_age(self): )) cid = self.s2i_app.get_cid(self.s2i_app.app_name) # Testing of not presence of a certificate in the production image - certificate_content = PodmanCLIWrapper.podman_exec_bash_command( + certificate_content = PodmanCLIWrapper.podman_exec_shell_command( cid_file_name=cid, cmd="cat \\$HTTPD_TLS_CERT_PATH/localhost.crt" - ).strip() + ) + assert certificate_content certificate_dir = tempfile.mkdtemp(prefix="/tmp/cert_dir") with open(Path(certificate_dir) / "cert", mode="w") as f: - f.write(certificate_content) + f.write(certificate_content.strip()) certificate_age_s = ContainerTestLibUtils.run_command( cmd=f"openssl x509 -startdate -noout -in {Path(certificate_dir)}/cert" ).strip().replace("notBefore=", "") @@ -125,10 +126,10 @@ def test_cert_age(self): # Testing whether the certificate was freshly generated after the image assert certificate_age < image_age # Testing presence and permissions of the generated certificate - assert PodmanCLIWrapper.podman_exec_bash_command( + assert PodmanCLIWrapper.podman_exec_shell_command( cid_file_name=cid, cmd="ls -l \\$HTTPD_TLS_CERT_PATH/localhost.crt" ) # Testing presence and permissions of the generated certificate - assert PodmanCLIWrapper.podman_exec_bash_command( + assert PodmanCLIWrapper.podman_exec_shell_command( cid_file_name=cid, cmd="ls -l \\$HTTPD_TLS_CERT_PATH/localhost.key" - ) + ) \ No newline at end of file From ff56ad5f26cfeb1969680a273abe22ff1841bb93 Mon Sep 17 00:00:00 2001 From: Petr Hracek Date: Fri, 26 Sep 2025 15:22:49 +0200 Subject: [PATCH 14/21] Update test/test_container_ssl.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Lumír 'Frenzy' Balhar --- test/test_container_ssl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_container_ssl.py b/test/test_container_ssl.py index 6b513b9c..aa65250e 100644 --- a/test/test_container_ssl.py +++ b/test/test_container_ssl.py @@ -42,7 +42,7 @@ def test_self_cert_test(self): cip = self.s2i_app.get_cip(cid_file_name=self.s2i_app.app_name) assert cip response = ".*" - assert self.s2i_app.test_response(url=f"{cip}", expected_code=200, expected_output=response) + assert self.s2i_app.test_response(url=cip, expected_code=200, expected_output=response) assert self.s2i_app.test_response(url=f"https://{cip}", port=8443, expected_output="SSL test works") server_cmd = f"openssl s_client -showcerts -servername {cip} -connect {cip}:8443 2>/dev/null" server_output = ContainerTestLibUtils.run_command(cmd=server_cmd) From 8760afbf3296c684b299ade0f4425182c587f87a Mon Sep 17 00:00:00 2001 From: Petr Hracek Date: Fri, 26 Sep 2025 15:23:05 +0200 Subject: [PATCH 15/21] Update test/test_container_httpd.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Lumír 'Frenzy' Balhar --- test/test_container_httpd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_container_httpd.py b/test/test_container_httpd.py index 5c355f98..a33aa724 100644 --- a/test/test_container_httpd.py +++ b/test/test_container_httpd.py @@ -57,7 +57,7 @@ def test_dockerfiles(self, dockerfile): assert self.app.test_app_dockerfile() cip = self.app.get_cip() assert cip - assert self.app.test_response(url=f"{cip}", expected_code=200, expected_output="Welcome to your static httpd application on OpenShift") + assert self.app.test_response(url=cip, expected_code=200, expected_output="Welcome to your static httpd application on OpenShift") @pytest.mark.parametrize( "mpm_config", From 2cd3c344854073248b2657ea4e15fa49e6c7ec2a Mon Sep 17 00:00:00 2001 From: Petr Hracek Date: Fri, 26 Sep 2025 15:23:18 +0200 Subject: [PATCH 16/21] Update test/test_container_httpd.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Lumír 'Frenzy' Balhar --- test/test_container_httpd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_container_httpd.py b/test/test_container_httpd.py index a33aa724..a32fd653 100644 --- a/test/test_container_httpd.py +++ b/test/test_container_httpd.py @@ -93,7 +93,7 @@ def test_log_to_data_volume(self): container_args=f"-e HTTPD_LOG_TO_VOLUME=1 --user 0 -v {data_dir}:/var/log/httpd" ) cip = self.app.get_cip(cid_file_name="test_log_dir") - assert self.app.test_response(url=f"{cip}", port=8080, expected_code=403) + assert self.app.test_response(url=cip, port=8080, expected_code=403) assert ContainerTestLibUtils.check_files_are_present( dir_name=data_dir, file_name_to_check=[ "access_log", From c30c0fadb7e544211706582c98602d9f9c7afce4 Mon Sep 17 00:00:00 2001 From: Petr Hracek Date: Fri, 26 Sep 2025 15:23:29 +0200 Subject: [PATCH 17/21] Update test/test_container_httpd.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Lumír 'Frenzy' Balhar --- test/test_container_httpd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_container_httpd.py b/test/test_container_httpd.py index a32fd653..1e13e1f4 100644 --- a/test/test_container_httpd.py +++ b/test/test_container_httpd.py @@ -120,4 +120,4 @@ def test_data_volume(self): ) cip = self.app.get_cip(cid_file_name="doc_root") assert cip - assert self.app.test_response(url=f"{cip}", port=8080, expected_code=200, expected_output="hello") + assert self.app.test_response(url=cip, port=8080, expected_code=200, expected_output="hello") From 652a4b88179cd85eee092b286c0098e2a308325f Mon Sep 17 00:00:00 2001 From: Petr Hracek Date: Fri, 26 Sep 2025 15:23:41 +0200 Subject: [PATCH 18/21] Update test/test_container_httpd.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Lumír 'Frenzy' Balhar --- test/test_container_httpd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_container_httpd.py b/test/test_container_httpd.py index 1e13e1f4..218dd290 100644 --- a/test/test_container_httpd.py +++ b/test/test_container_httpd.py @@ -74,7 +74,7 @@ def test_mpm_config(self, mpm_config): # Let's check that server really response HTTP-403 # See function here: in test/run `_run_mpm_config_test` # https://github.com/sclorg/httpd-container/blob/master/test/run#L97 - assert self.app.test_response(url=f"{cip}", port=8080, expected_code=403) + assert self.app.test_response(url=cip, port=8080, expected_code=403) logs = self.app.get_logs(cid_file_name=cid_name) assert re.search(f"mpm_{mpm_config}:notice.*resuming normal operations", logs) From 6afdb15870d81b43ee72f704623e766b241fcd87 Mon Sep 17 00:00:00 2001 From: "Petr \"Stone\" Hracek" Date: Mon, 29 Sep 2025 10:58:27 +0200 Subject: [PATCH 19/21] PyTest suite test_container_ssl.py was removed. The whole suite was added to test_container_httpd_s2i.py. Also building new image is called by new function. Now each class use this function. Check of SSL should pass with proper response. Signed-off-by: Petr "Stone" Hracek --- 2.4-micro/test/test_container_ssl.py | 1 - 2.4/test/test_container_ssl.py | 1 - test/test_container_httpd.py | 7 +- test/test_container_httpd_s2i.py | 95 ++++++++++++++++++---------- test/test_container_ssl.py | 57 ----------------- 5 files changed, 66 insertions(+), 95 deletions(-) delete mode 120000 2.4-micro/test/test_container_ssl.py delete mode 120000 2.4/test/test_container_ssl.py delete mode 100644 test/test_container_ssl.py diff --git a/2.4-micro/test/test_container_ssl.py b/2.4-micro/test/test_container_ssl.py deleted file mode 120000 index 4257c464..00000000 --- a/2.4-micro/test/test_container_ssl.py +++ /dev/null @@ -1 +0,0 @@ -../../test/test_container_ssl.py \ No newline at end of file diff --git a/2.4/test/test_container_ssl.py b/2.4/test/test_container_ssl.py deleted file mode 120000 index 4257c464..00000000 --- a/2.4/test/test_container_ssl.py +++ /dev/null @@ -1 +0,0 @@ -../../test/test_container_ssl.py \ No newline at end of file diff --git a/test/test_container_httpd.py b/test/test_container_httpd.py index 218dd290..7c60d134 100644 --- a/test/test_container_httpd.py +++ b/test/test_container_httpd.py @@ -1,4 +1,5 @@ import os +import sys import re import tempfile @@ -7,7 +8,11 @@ import pytest from container_ci_suite.container_lib import ContainerTestLib -from container_ci_suite.utils import ContainerTestLibUtils +from container_ci_suite.utils import ContainerTestLibUtils, check_variables + + +if not check_variables(): + sys.exit(1) TEST_DIR = Path(__file__).parent.absolute() diff --git a/test/test_container_httpd_s2i.py b/test/test_container_httpd_s2i.py index a14487b9..41311663 100644 --- a/test/test_container_httpd_s2i.py +++ b/test/test_container_httpd_s2i.py @@ -1,37 +1,44 @@ import os +import sys import time import tempfile from pathlib import Path from container_ci_suite.container_lib import ContainerTestLib -from container_ci_suite.utils import ContainerTestLibUtils +from container_ci_suite.utils import ContainerTestLibUtils, check_variables from container_ci_suite.engines.podman_wrapper import PodmanCLIWrapper +if not check_variables(): + sys.exit(1) TEST_DIR = Path(__file__).parent.absolute() VERSION = os.getenv("VERSION") -OS = os.getenv("TARGET") +OS = os.getenv("OS").lower() IMAGE_NAME = os.getenv("IMAGE_NAME") pre_init_test_app = TEST_DIR / "pre-init-test-app" sample_test_app = TEST_DIR / "sample-test-app" +self_cert_test = TEST_DIR / "self-signed-ssl" + + +def build_s2i_app(app_path: Path) -> ContainerTestLib: + container_lib = ContainerTestLib(IMAGE_NAME) + app_name = app_path.name + s2i_app = container_lib.build_as_df( + app_path=app_path, + s2i_args="--pull-policy=never", + src_image=IMAGE_NAME, + dst_image=f"{IMAGE_NAME}-{app_name}" + ) + return s2i_app class TestHttpdS2IPreInitContainer: def setup_method(self): - self.container_lib = ContainerTestLib(IMAGE_NAME) - print(self.container_lib) - app_name = pre_init_test_app.name - print(app_name) - self.s2i_app = self.container_lib.build_as_df( - app_path=pre_init_test_app, - s2i_args="--pull-policy=never", - src_image=IMAGE_NAME, - dst_image=f"{IMAGE_NAME}-{app_name}" - ) + self.s2i_app = build_s2i_app(pre_init_test_app) def teardown_method(self): self.s2i_app.cleanup() @@ -50,14 +57,7 @@ def test_run_pre_init_test(self): class TestHttpdS2ISampleAppContainer: def setup_method(self): - self.ci = ContainerTestLib(IMAGE_NAME) - app_name = sample_test_app.name - self.s2i_app = self.ci.build_as_df( - app_path=sample_test_app, - s2i_args="--pull-policy=never", - src_image=IMAGE_NAME, - dst_image=f"{IMAGE_NAME}-{app_name}" - ) + self.s2i_app = build_s2i_app(sample_test_app) def teardown_method(self): self.s2i_app.cleanup() @@ -82,25 +82,18 @@ def test_sample_app(self): class TestHttpdCertAgeContainer: def setup_method(self): - self.ci = ContainerTestLib(IMAGE_NAME) - app_name = sample_test_app.name - self.s2i_app = self.ci.build_as_df( - app_path=sample_test_app, - s2i_args="--pull-policy=never", - src_image=IMAGE_NAME, - dst_image=f"{IMAGE_NAME}-{app_name}" - ) + self.s2i_app = build_s2i_app(sample_test_app) def teardown_method(self): self.s2i_app.cleanup() - """ - This tests checks whether the certificate was freshly generated after the image - We need to make sure the certificate is generated no sooner than in assemble phase, - because shipping the same certs in the image would make it easy to exploit - Let's see how old the certificate is and compare with how old the image is - """ def test_cert_age(self): + """ + This tests checks whether the certificate was freshly generated after the image + We need to make sure the certificate is generated no sooner than in assemble phase, + because shipping the same certs in the image would make it easy to exploit + Let's see how old the certificate is and compare with how old the image is + """ assert self.s2i_app.create_container(cid_file_name=self.s2i_app.app_name, container_args="--user 1000") image_age_s = PodmanCLIWrapper.podman_inspect( field="{{.Created}}", src_image=IMAGE_NAME @@ -132,4 +125,36 @@ def test_cert_age(self): # Testing presence and permissions of the generated certificate assert PodmanCLIWrapper.podman_exec_shell_command( cid_file_name=cid, cmd="ls -l \\$HTTPD_TLS_CERT_PATH/localhost.key" - ) \ No newline at end of file + ) + +class TestHttpdS2ISslSelfSignedAppContainer: + + def setup_method(self): + self.s2i_app = build_s2i_app(self_cert_test) + + def teardown_method(self): + self.s2i_app.cleanup() + + def test_self_cert_test(self): + """ + Test s2i use case #3 - using own ssl certs + Since we built the candidate image locally, we don't want S2I attempt to pull + it from Docker hub + """ + self.s2i_app.set_new_image(image_name=f"{IMAGE_NAME}-{self.s2i_app.app_name}") + assert self.s2i_app.create_container(cid_file_name=self.s2i_app.app_name, container_args="--user 1000") + cip = self.s2i_app.get_cip(cid_file_name=self.s2i_app.app_name) + assert cip + assert self.s2i_app.test_response(url=cip, expected_code=200, expected_output="SSL test works") + assert self.s2i_app.test_response(url=f"https://{cip}", port=8443, expected_output="SSL test works") + server_cmd = f"openssl s_client -showcerts -servername {cip} -connect {cip}:8443 2>/dev/null" + server_output = ContainerTestLibUtils.run_command(cmd=server_cmd) + certificate_dir = tempfile.mkdtemp(prefix="/tmp/server_cert_dir") + with open(Path(certificate_dir) / "output", mode="wt+") as f: + f.write(server_output) + server_cert = ContainerTestLibUtils.run_command( + cmd=f"openssl x509 -inform pem -noout -text -in {Path(certificate_dir)}/output" + ) + config_cmd = f"openssl x509 -in {TEST_DIR}/{self.s2i_app.app_name}/httpd-ssl/certs/server-cert-selfsigned.pem -inform pem -noout -text" + config_cert = ContainerTestLibUtils.run_command(cmd=config_cmd) + assert server_cert == config_cert diff --git a/test/test_container_ssl.py b/test/test_container_ssl.py deleted file mode 100644 index aa65250e..00000000 --- a/test/test_container_ssl.py +++ /dev/null @@ -1,57 +0,0 @@ -import os -import tempfile - -from pathlib import Path - -from container_ci_suite.container_lib import ContainerTestLib -from container_ci_suite.utils import ContainerTestLibUtils - - -TEST_DIR = Path(__file__).parent.absolute() -VERSION = os.getenv("VERSION") -OS = os.getenv("TARGET") -IMAGE_NAME = os.getenv("IMAGE_NAME") - - -self_cert_test = TEST_DIR / "self-signed-ssl" - - -class TestHttpdS2ISslSelfSignedAppContainer: - - def setup_method(self): - self.ci = ContainerTestLib(IMAGE_NAME) - app_name = self_cert_test.name - self.s2i_app = self.ci.build_as_df( - app_path=self_cert_test, - s2i_args="--pull-policy=never", - src_image=IMAGE_NAME, - dst_image=f"{IMAGE_NAME}-{app_name}" - ) - - def teardown_method(self): - self.s2i_app.cleanup() - - """ - Test s2i use case #3 - using own ssl certs - Since we built the candidate image locally, we don't want S2I attempt to pull - it from Docker hub - """ - def test_self_cert_test(self): - self.s2i_app.set_new_image(image_name=f"{IMAGE_NAME}-{self.s2i_app.app_name}") - assert self.s2i_app.create_container(cid_file_name=self.s2i_app.app_name, container_args="--user 1000") - cip = self.s2i_app.get_cip(cid_file_name=self.s2i_app.app_name) - assert cip - response = ".*" - assert self.s2i_app.test_response(url=cip, expected_code=200, expected_output=response) - assert self.s2i_app.test_response(url=f"https://{cip}", port=8443, expected_output="SSL test works") - server_cmd = f"openssl s_client -showcerts -servername {cip} -connect {cip}:8443 2>/dev/null" - server_output = ContainerTestLibUtils.run_command(cmd=server_cmd) - certificate_dir = tempfile.mkdtemp(prefix="/tmp/server_cert_dir") - with open(Path(certificate_dir) / "output", mode="wt+") as f: - f.write(server_output) - server_cert = ContainerTestLibUtils.run_command( - cmd=f"openssl x509 -inform pem -noout -text -in {Path(certificate_dir)}/output" - ) - config_cmd = f"openssl x509 -in {TEST_DIR}/{self.s2i_app.app_name}/httpd-ssl/certs/server-cert-selfsigned.pem -inform pem -noout -text" - config_cert = ContainerTestLibUtils.run_command(cmd=config_cmd) - assert server_cert == config_cert From f292ca0ae1053c498a987cbceefea457780e30e0 Mon Sep 17 00:00:00 2001 From: "Petr \"Stone\" Hracek" Date: Mon, 29 Sep 2025 11:03:48 +0200 Subject: [PATCH 20/21] Update comments in PyTest suite. Signed-off-by: Petr "Stone" Hracek --- test/test_container_httpd_s2i.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/test_container_httpd_s2i.py b/test/test_container_httpd_s2i.py index 41311663..f1183c4c 100644 --- a/test/test_container_httpd_s2i.py +++ b/test/test_container_httpd_s2i.py @@ -89,7 +89,6 @@ def teardown_method(self): def test_cert_age(self): """ - This tests checks whether the certificate was freshly generated after the image We need to make sure the certificate is generated no sooner than in assemble phase, because shipping the same certs in the image would make it easy to exploit Let's see how old the certificate is and compare with how old the image is @@ -137,9 +136,9 @@ def teardown_method(self): def test_self_cert_test(self): """ - Test s2i use case #3 - using own ssl certs - Since we built the candidate image locally, we don't want S2I attempt to pull - it from Docker hub + Test s2i use case #3 - using own ssl certs + Since we built the candidate image locally, we don't want S2I attempt to pull + it from Docker hub """ self.s2i_app.set_new_image(image_name=f"{IMAGE_NAME}-{self.s2i_app.app_name}") assert self.s2i_app.create_container(cid_file_name=self.s2i_app.app_name, container_args="--user 1000") From 5b8ad705ffa616674c5331ecc919ee85e50773a7 Mon Sep 17 00:00:00 2001 From: "Petr \"Stone\" Hracek" Date: Mon, 29 Sep 2025 13:02:10 +0200 Subject: [PATCH 21/21] Add settings.py that gets environment variables like IMAGE_NAME, OS, VERSION and import them in PyTest suite Signed-off-by: Petr "Stone" Hracek --- 2.4-micro/test/settings.py | 1 + 2.4/test/settings.py | 1 + test/settings.py | 9 +++++++++ test/test_container_httpd.py | 16 ++-------------- test/test_container_httpd_s2i.py | 13 ++----------- 5 files changed, 15 insertions(+), 25 deletions(-) create mode 120000 2.4-micro/test/settings.py create mode 120000 2.4/test/settings.py create mode 100644 test/settings.py diff --git a/2.4-micro/test/settings.py b/2.4-micro/test/settings.py new file mode 120000 index 00000000..44504a45 --- /dev/null +++ b/2.4-micro/test/settings.py @@ -0,0 +1 @@ +../../test/settings.py \ No newline at end of file diff --git a/2.4/test/settings.py b/2.4/test/settings.py new file mode 120000 index 00000000..44504a45 --- /dev/null +++ b/2.4/test/settings.py @@ -0,0 +1 @@ +../../test/settings.py \ No newline at end of file diff --git a/test/settings.py b/test/settings.py new file mode 100644 index 00000000..20ab0b44 --- /dev/null +++ b/test/settings.py @@ -0,0 +1,9 @@ +import os + +from pathlib import Path + + +VERSION = os.getenv("VERSION") +OS = os.getenv("OS").lower() +IMAGE_NAME = os.getenv("IMAGE_NAME") +TEST_DIR = Path(__file__).parent.absolute() diff --git a/test/test_container_httpd.py b/test/test_container_httpd.py index 7c60d134..0811e6e4 100644 --- a/test/test_container_httpd.py +++ b/test/test_container_httpd.py @@ -1,24 +1,12 @@ -import os -import sys import re import tempfile -from pathlib import Path - import pytest from container_ci_suite.container_lib import ContainerTestLib -from container_ci_suite.utils import ContainerTestLibUtils, check_variables - - -if not check_variables(): - sys.exit(1) - +from container_ci_suite.utils import ContainerTestLibUtils -TEST_DIR = Path(__file__).parent.absolute() -VERSION = os.getenv("VERSION") -OS = os.getenv("OS").lower() -IMAGE_NAME = os.getenv("IMAGE_NAME") +from settings import IMAGE_NAME, TEST_DIR class TestHttpdAppContainer: diff --git a/test/test_container_httpd_s2i.py b/test/test_container_httpd_s2i.py index f1183c4c..d29b1b4c 100644 --- a/test/test_container_httpd_s2i.py +++ b/test/test_container_httpd_s2i.py @@ -1,22 +1,13 @@ -import os -import sys import time import tempfile from pathlib import Path from container_ci_suite.container_lib import ContainerTestLib -from container_ci_suite.utils import ContainerTestLibUtils, check_variables +from container_ci_suite.utils import ContainerTestLibUtils from container_ci_suite.engines.podman_wrapper import PodmanCLIWrapper -if not check_variables(): - sys.exit(1) - -TEST_DIR = Path(__file__).parent.absolute() -VERSION = os.getenv("VERSION") -OS = os.getenv("OS").lower() -IMAGE_NAME = os.getenv("IMAGE_NAME") - +from settings import IMAGE_NAME, TEST_DIR pre_init_test_app = TEST_DIR / "pre-init-test-app" sample_test_app = TEST_DIR / "sample-test-app"