-
Notifications
You must be signed in to change notification settings - Fork 125
Testing httpd-2.4 container by PyTest #234
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
Changes from all commits
6737b7f
6d5f823
884569a
00573a2
ee7ccfd
ea65bf9
b1e158e
3ea9aed
1b6e27d
db4b466
0ad18a8
83e280e
8862757
ff56ad5
8760afb
2cd3c34
c30c0fa
652a4b8
6afdb15
f292ca0
5b8ad70
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ../../test/run-pytest |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ../../test/settings.py |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ../../test/test_container_httpd.py |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ../../test/test_container_httpd_s2i.py |
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ../../test/test_ocp_ex_template.py |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ../../test/test_ocp_imagestream_s2i.py |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ../../test/test_ocp_imagestreams.py |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ../../test/test_ocp_integration.py |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ../../test/test_ocp_shared_helm_imagestreams.py |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ../../test/test_ocp_shared_helm_template.py |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ../../test/run-pytest |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ../../test/settings.py |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ../../test/test_container_httpd.py |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ../../test/test_container_httpd_s2i.py |
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ../../test/test_ocp_ex_template.py |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ../../test/test_ocp_imagestream_s2i.py |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ../../test/test_ocp_imagestreams.py |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ../../test/test_ocp_integration.py |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ../../test/test_ocp_shared_helm_imagestreams.py |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ../../test/test_ocp_shared_helm_template.py |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 httpd | ||
| # 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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,116 @@ | ||
| import re | ||
| import tempfile | ||
|
|
||
| import pytest | ||
|
|
||
| from container_ci_suite.container_lib import ContainerTestLib | ||
| from container_ci_suite.utils import ContainerTestLibUtils | ||
|
|
||
| from settings import IMAGE_NAME, TEST_DIR | ||
|
|
||
|
|
||
| class TestHttpdAppContainer: | ||
|
|
||
| def setup_method(self): | ||
| self.app = ContainerTestLib(image_name=IMAGE_NAME, s2i_image=True) | ||
|
|
||
| def teardown_method(self): | ||
| self.app.cleanup() | ||
|
|
||
| @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 | ||
| 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( | ||
| "dockerfile", | ||
| [ | ||
| "Dockerfile", | ||
| "Dockerfile.s2i" | ||
| ] | ||
| ) | ||
| 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 self.app.test_app_dockerfile() | ||
| cip = self.app.get_cip() | ||
| assert cip | ||
| 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", | ||
| [ | ||
| "worker", | ||
| "event", | ||
| "prefork", | ||
| ] | ||
| ) | ||
| def test_mpm_config(self, mpm_config): | ||
| cid_name = f"test_mpm_{mpm_config}" | ||
| 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 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) | ||
|
|
||
|
|
||
| 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}", | ||
| f"chown -R 1001:1001 {data_dir}", | ||
| f"chcon -Rvt svirt_sandbox_file_t {data_dir}/" | ||
| ] | ||
| ) | ||
| 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 = self.app.get_cip(cid_file_name="test_log_dir") | ||
| 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", | ||
| "error_log", | ||
| "ssl_access_log", | ||
| "ssl_error_log", | ||
| "ssl_request_log", | ||
| ] | ||
| ) | ||
|
|
||
| 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", | ||
| 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 self.app.create_container( | ||
| cid_file_name="doc_root", | ||
| container_args=f"-v {data_dir}:/var/www" | ||
| ) | ||
| cip = self.app.get_cip(cid_file_name="doc_root") | ||
| assert cip | ||
| assert self.app.test_response(url=cip, port=8080, expected_code=200, expected_output="hello") |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,150 @@ | ||
| 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.engines.podman_wrapper import PodmanCLIWrapper | ||
|
|
||
| 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" | ||
| 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.s2i_app = build_s2i_app(pre_init_test_app) | ||
|
|
||
| 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 | ||
| assert self.s2i_app.test_response( | ||
| url=cip, | ||
| expected_code=200, | ||
| expected_output="This content was replaced by pre-init script." | ||
| ) | ||
|
|
||
|
|
||
| class TestHttpdS2ISampleAppContainer: | ||
|
|
||
| def setup_method(self): | ||
| self.s2i_app = build_s2i_app(sample_test_app) | ||
|
|
||
| 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 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.s2i_app = build_s2i_app(sample_test_app) | ||
|
|
||
| def teardown_method(self): | ||
| self.s2i_app.cleanup() | ||
|
|
||
| def test_cert_age(self): | ||
| """ | ||
| 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 | ||
| ).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_shell_command( | ||
| cid_file_name=cid, cmd="cat \\$HTTPD_TLS_CERT_PATH/localhost.crt" | ||
| ) | ||
| 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.strip()) | ||
| certificate_age_s = ContainerTestLibUtils.run_command( | ||
| cmd=f"openssl x509 -startdate -noout -in {Path(certificate_dir)}/cert" | ||
| ).strip().replace("notBefore=", "") | ||
phracek marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| 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_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_shell_command( | ||
| cid_file_name=cid, cmd="ls -l \\$HTTPD_TLS_CERT_PATH/localhost.key" | ||
| ) | ||
|
|
||
| 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 | ||
Uh oh!
There was an error while loading. Please reload this page.