Skip to content

Commit f1553ff

Browse files
VED-1085 Fix intermittent connection closed e2e test issue (#1250)
Co-authored-by: Ed Hall <239591530+edhall-nhs@users.noreply.github.com>
1 parent a4bd111 commit f1553ff

1 file changed

Lines changed: 35 additions & 13 deletions

File tree

tests/e2e_automation/utilities/apigee/ApigeeOnDemandAppManager.py

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import uuid
44

55
import requests
6+
from requests.adapters import HTTPAdapter
7+
from urllib3 import Retry
68

79
from utilities.apigee.apigee_env_helpers import (
810
get_apigee_access_token,
@@ -12,6 +14,9 @@
1214
)
1315
from utilities.apigee.ApigeeApp import ApigeeApp
1416

17+
_DEFAULT_RETRIES = 3
18+
_DEFAULT_TIMEOUT_SECONDS = 10
19+
1520

1621
class ApigeeOnDemandAppManager:
1722
"""Manager class that provides required Apigee functionality for Apigee non-prod env e2e tests, e.g. creating an
@@ -25,20 +30,28 @@ class ApigeeOnDemandAppManager:
2530
_INTERNAL_DEV_ID_SERVICE_PRODUCT = "identity-service-internal-dev"
2631
_TEST_APP_SUPPLIERS = ("EMIS", "MAVIS", "MEDICUS", "Postman_Auth", "RAVS", "SONAR", "TPP")
2732

28-
def __init__(self):
33+
def __init__(self, retries: int = _DEFAULT_RETRIES, timeout: int = _DEFAULT_TIMEOUT_SECONDS):
2934
self.proxy_name = get_proxy_name()
3035
self.apigee_environment = get_apigee_environment()
3136
self.created_product_name_uuid: str = ""
3237
self.created_app_name_uuids = []
3338
self.display_name = f"test-{self.proxy_name}"
39+
self.retries = retries
40+
self.timeout = timeout
3441

3542
self.logged_in_username = get_apigee_username()
3643
self.access_token = get_apigee_access_token()
3744

38-
self.requests_session = requests.Session()
39-
self.requests_session.headers.update({"Authorization": f"Bearer {self.access_token}"})
45+
def _build_req_session(self) -> requests.Session:
46+
"""Creates a fresh requests.Session with basic retry behaviour and the Apigee auth header set. A new session
47+
should be created for teardown as long-lived connections may be closed."""
48+
requests_session = requests.Session()
49+
requests_session.mount("https://", HTTPAdapter(max_retries=Retry(total=self.retries, backoff_factor=1)))
50+
requests_session.headers.update({"Authorization": f"Bearer {self.access_token}"})
51+
52+
return requests_session
4053

41-
def _create_app(self, target_product_name: str, supplier_name: str) -> ApigeeApp:
54+
def _create_app(self, target_product_name: str, supplier_name: str, http_session: requests.Session) -> ApigeeApp:
4255
app_name_uuid = str(uuid.uuid4())
4356
app_data = {
4457
"name": app_name_uuid,
@@ -51,8 +64,10 @@ def _create_app(self, target_product_name: str, supplier_name: str) -> ApigeeApp
5164
"apiProducts": [target_product_name, self._INTERNAL_DEV_ID_SERVICE_PRODUCT],
5265
}
5366

54-
response = self.requests_session.post(
55-
url=f"{self._BASE_URL}/{self._DEVELOPERS_PATH}/{self.logged_in_username}/{self._APPS_PATH}", json=app_data
67+
response = http_session.post(
68+
url=f"{self._BASE_URL}/{self._DEVELOPERS_PATH}/{self.logged_in_username}/{self._APPS_PATH}",
69+
json=app_data,
70+
timeout=self.timeout,
5671
)
5772
response.raise_for_status()
5873

@@ -66,7 +81,7 @@ def _create_app(self, target_product_name: str, supplier_name: str) -> ApigeeApp
6681
supplier=supplier_name,
6782
)
6883

69-
def _create_product(self) -> str:
84+
def _create_product(self, http_session: requests.Session) -> str:
7085
product_name_uuid = str(uuid.uuid4())
7186
apigee_product_data = {
7287
"name": product_name_uuid,
@@ -82,9 +97,10 @@ def _create_product(self) -> str:
8297
],
8398
}
8499

85-
response = self.requests_session.post(
100+
response = http_session.post(
86101
url=f"{self._BASE_URL}/{self._PRODUCTS_PATH}",
87102
json=apigee_product_data,
103+
timeout=self.timeout,
88104
)
89105
response.raise_for_status()
90106

@@ -93,19 +109,25 @@ def _create_product(self) -> str:
93109

94110
def setup_apps_and_product(self) -> list[ApigeeApp]:
95111
"""Orchestration method to set up the required product and on-demand apps required for PR testing"""
112+
http_session = self._build_req_session()
96113
created_apps: list[ApigeeApp] = []
97-
product_name_uuid = self._create_product()
114+
product_name_uuid = self._create_product(http_session)
98115

99116
for supplier_name in self._TEST_APP_SUPPLIERS:
100-
created_apps.append(self._create_app(product_name_uuid, supplier_name))
117+
created_apps.append(self._create_app(product_name_uuid, supplier_name, http_session))
101118

119+
http_session.close()
102120
return created_apps
103121

104122
def teardown_apps_and_product(self):
105123
"""Orchestration method to remove the Apigee resources in a teardown step"""
124+
http_session = self._build_req_session()
125+
106126
for created_app_name_uuid in self.created_app_name_uuids:
107-
self.requests_session.delete(
108-
url=f"{self._BASE_URL}/{self._DEVELOPERS_PATH}/{self.logged_in_username}/{self._APPS_PATH}/{created_app_name_uuid}"
127+
http_session.delete(
128+
url=f"{self._BASE_URL}/{self._DEVELOPERS_PATH}/{self.logged_in_username}/{self._APPS_PATH}/{created_app_name_uuid}",
129+
timeout=self.timeout,
109130
)
110131

111-
self.requests_session.delete(url=f"{self._BASE_URL}/{self._PRODUCTS_PATH}/{self.created_product_name_uuid}")
132+
http_session.delete(url=f"{self._BASE_URL}/{self._PRODUCTS_PATH}/{self.created_product_name_uuid}")
133+
http_session.close()

0 commit comments

Comments
 (0)