From aa64ea3f1e34f6ea83a3b5692c4d7d7fea96c344 Mon Sep 17 00:00:00 2001 From: Ales Nezbeda Date: Wed, 4 Dec 2024 09:48:22 +0100 Subject: [PATCH 1/2] Refactor test_response to use Requests instead of curl --- container_ci_suite/engines/s2i_container.py | 80 ++++++++++----------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/container_ci_suite/engines/s2i_container.py b/container_ci_suite/engines/s2i_container.py index 2f418cb..91a5078 100644 --- a/container_ci_suite/engines/s2i_container.py +++ b/container_ci_suite/engines/s2i_container.py @@ -28,6 +28,7 @@ import time import subprocess import shutil +import requests from typing import List from os import getenv @@ -464,49 +465,48 @@ def doc_content_old(self, strings: List) -> bool: # } def test_response( - self, url: str = "", - expected_code: int = 200, port: int = 8080, - expected_output: str = "", max_tests: int = 20 + self, url: str = "", port: int = 8080, + expected_code: int = 200, expected_output: str = "", + max_tests: int = 20 ) -> bool: - url = f"{url}:{port}" + """ + Test HTTP response of specified url + + If expected output is empty, check will be skipped + + Args: + url (str): URL where to send request + port (int): Port of the web service + expected_code (int): Check that response has this code + expected_output (str): Check that response has this text + max_tests (int): Stop after this many unsuccessful tries + """ + + url = f"http://{url}:{port}" print(f"URL address to get response from container: {url}") - cmd_to_run = "curl --connect-timeout 10 -k -s -w '%{http_code}' " + f"{url}" - # Check if application returns proper HTTP_CODE - print("Check if HTTP_CODE is valid.") - for count in range(max_tests): + + try: + response = requests.get(url, timeout=10) + except requests.exceptions.ConnectionError: + response = None + + while (response is not None and + response.status_code != expected_code and + (response.text != expected_output or expected_output == "") and + max_tests > 0): + print(f"Unexpected code {response.status_code} or output \ + {response.text}, expecting \ + {expected_code} {expected_output}") + max_tests -= 1 try: - output_code = run_command(cmd=f"{cmd_to_run}", return_output=True) - return_code = output_code[-3:] - print(f"Output is: {output_code} and Return Code is: {return_code}") - try: - int_ret_code = int(return_code) - if int_ret_code == expected_code: - print(f"HTTP_CODE is VALID {int_ret_code}") - break - except ValueError: - logger.info(return_code) - time.sleep(1) - continue - time.sleep(3) - continue - except subprocess.CalledProcessError as cpe: - print(f"Error from {cmd_to_run} is {cpe.stderr}, {cpe.stdout}") - time.sleep(3) - - cmd_to_run = "curl --connect-timeout 10 -k -s " + f"{url}" - # Check if application returns proper output - for count in range(max_tests): - output_code = run_command(cmd=f"{cmd_to_run}", return_output=True) - print(f"Check if expected output {expected_output} is in {cmd_to_run}.") - if expected_output in output_code: - print(f"Expected output '{expected_output}' is present.") - return True - print( - f"check_response_inside_cluster:" - f"expected_output {expected_output} not found in output of {cmd_to_run} command. See {output_code}" - ) - time.sleep(5) - return False + response = requests.get(url, timeout=10) + except requests.exceptions.ConnectionError: + response = None + time.sleep(3) + + return response is not None and \ + response.status_code != expected_code and \ + (response.text != expected_output or expected_output == "") # Replacement for ct_check_exec_env_vars def test_check_exec_env_vars(self, env_filter: str = "^X_SCLS=|/opt/rh|/opt/app-root"): From 67179f03314b67f30a722bd627baa8d91dc1ef3e Mon Sep 17 00:00:00 2001 From: Ales Nezbeda Date: Wed, 4 Dec 2024 13:04:38 +0100 Subject: [PATCH 2/2] Make while clause simpler, use logger instead of print. --- container_ci_suite/engines/s2i_container.py | 48 +++++++++++++-------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/container_ci_suite/engines/s2i_container.py b/container_ci_suite/engines/s2i_container.py index 91a5078..a08920d 100644 --- a/container_ci_suite/engines/s2i_container.py +++ b/container_ci_suite/engines/s2i_container.py @@ -483,30 +483,44 @@ def test_response( """ url = f"http://{url}:{port}" - print(f"URL address to get response from container: {url}") + logger.debug("URL address to get response from container: %s", url) - try: - response = requests.get(url, timeout=10) - except requests.exceptions.ConnectionError: - response = None - - while (response is not None and - response.status_code != expected_code and - (response.text != expected_output or expected_output == "") and - max_tests > 0): - print(f"Unexpected code {response.status_code} or output \ - {response.text}, expecting \ - {expected_code} {expected_output}") - max_tests -= 1 + response = None + checks_passed = False + while not checks_passed and max_tests > 0: + checks_passed = True try: response = requests.get(url, timeout=10) except requests.exceptions.ConnectionError: response = None + + if response is None: + checks_passed = False + + # This will very probably timeout first few times and it is + # expected to do so. Prevent spam and inform only when timeout + # is fatal. + if max_tests == 1: + logger.error("Timeout on last retry") + else: + if response.status_code != expected_code: + checks_passed = False + if (response.text != expected_output and + expected_output != ""): + checks_passed = False + + # Log both code and text together as text can show error + # message + if not checks_passed: + logger.error("Unexpected code %d or output %s, \ + expecting %d %s", + response.status_code, response.text, + expected_code, expected_output) + + max_tests -= 1 time.sleep(3) - return response is not None and \ - response.status_code != expected_code and \ - (response.text != expected_output or expected_output == "") + return checks_passed # Replacement for ct_check_exec_env_vars def test_check_exec_env_vars(self, env_filter: str = "^X_SCLS=|/opt/rh|/opt/app-root"):