From 2c1c0d9aa222ce771c9b7b44662603d3af15bffb Mon Sep 17 00:00:00 2001 From: Gokula Krishnan <67802669+gokulakrishnansvm@users.noreply.github.com> Date: Fri, 16 Jun 2023 22:02:20 +0530 Subject: [PATCH] Added API contract testcase for Jobs endpoint (#7573) * Added Jobs TC * modified code * Reactored code and added deletion of prerequisites data after every test case execution * Added logging for deletion of prerequisites endpoint data and resolved pylint errors * Added fixture names * Refactored coordinates TC * Removed unnecessary comments --- .../testing/api_contract/v4/conftest.py | 287 +++++++++++++----- .../v4/data/request_template.json | 9 + .../v4/data/response_template.json | 35 +++ .../testing/api_contract/v4/test_asns.py | 11 - .../api_contract/v4/test_cachegroups.py | 6 - .../testing/api_contract/v4/test_cdns.py | 6 - .../api_contract/v4/test_coordinates.py | 6 - .../api_contract/v4/test_delivery_services.py | 16 - .../testing/api_contract/v4/test_divisions.py | 6 - .../testing/api_contract/v4/test_jobs.py | 76 +++++ .../testing/api_contract/v4/test_origins.py | 11 - .../api_contract/v4/test_parameters.py | 6 - .../api_contract/v4/test_phys_locations.py | 11 - .../testing/api_contract/v4/test_profiles.py | 11 - .../testing/api_contract/v4/test_regions.py | 11 - .../testing/api_contract/v4/test_roles.py | 6 - .../v4/test_server_capabilities.py | 6 - .../testing/api_contract/v4/test_servers.py | 30 +- .../testing/api_contract/v4/test_statuses.py | 8 - .../testing/api_contract/v4/test_tenants.py | 6 - 20 files changed, 332 insertions(+), 232 deletions(-) create mode 100644 traffic_ops/testing/api_contract/v4/test_jobs.py diff --git a/traffic_ops/testing/api_contract/v4/conftest.py b/traffic_ops/testing/api_contract/v4/conftest.py index b75e45e0b4..1eebf00f4a 100644 --- a/traffic_ops/testing/api_contract/v4/conftest.py +++ b/traffic_ops/testing/api_contract/v4/conftest.py @@ -19,6 +19,7 @@ import json import logging +import shutil import sys import os from random import randint @@ -108,6 +109,15 @@ def __str__(self) -> str: ArgsType.port.__doc__ = """The port number on which to connect to Traffic Ops.""" ArgsType.api_version.__doc__ = """The version number of the API to use.""" + +@pytest.fixture(autouse=True, scope='function') +def delete_pytest_cache(): + """ + Deletes cached data before every test case execution + """ + shutil.rmtree(".pytest_cache", ignore_errors=True) + + def pytest_addoption(parser: pytest.Parser) -> None: """ Parses the Traffic Ops arguments from command line. @@ -457,8 +467,8 @@ def check_template_data(template_data: Union[list[JSONData], tuple[JSONData, req @pytest.fixture(name="cdn_post_data") -def cdn_data_post(to_session: TOSession, request_template_data: list[JSONData] - ) -> dict[str, object]: +def cdn_data_post(to_session: TOSession, request_template_data: list[JSONData], + pytestconfig: pytest.Config) -> dict[str, object]: """ PyTest Fixture to create POST data for cdns endpoint. @@ -486,12 +496,19 @@ def cdn_data_post(to_session: TOSession, request_template_data: list[JSONData] # Hitting cdns POST methed response: tuple[JSONData, requests.Response] = to_session.create_cdn(data=cdn) resp_obj = check_template_data(response, "cdns") - return resp_obj + pytestconfig.cache.set("cdnDomainName",resp_obj.get("domainName")) + yield resp_obj + cdn_id = resp_obj.get("id") + msg = to_session.delete_cdn_by_id(cdn_id=cdn_id) + logger.info("Deleting cdn data... %s", msg) + if msg is None: + logger.error("Cdn returned by Traffic Ops is missing an 'id' property") + pytest.fail("Response from delete request is empty, Failing test_case") @pytest.fixture(name="cache_group_post_data") -def cache_group_data_post(to_session: TOSession, request_template_data: list[JSONData] - ) -> dict[str, object]: +def cache_group_data_post(to_session: TOSession, request_template_data: list[JSONData], + pytestconfig: pytest.Config) -> dict[str, object]: """ PyTest Fixture to create POST data for cachegroup endpoint. @@ -515,20 +532,30 @@ def cache_group_data_post(to_session: TOSession, request_template_data: list[JSO raise TypeError(f"missing Cache group property '{e.args[0]}'") from e # Check if type already exists, otherwise create it - type_data = check_template_data(request_template_data["types"], "types") - type_object = create_or_get_existing(to_session, "types", "type", type_data, + type_id = pytestconfig.cache.get("typeId", default=None) + if type_id: + cache_group["typeId"] = type_id + else: + type_data = check_template_data(request_template_data["types"], "types") + type_object = create_or_get_existing(to_session, "types", "type", type_data, {"useInTable": "cachegroup"}) - cache_group["typeId"] = type_object["id"] + cache_group["typeId"] = type_object["id"] logger.info("New cachegroup data to hit POST method %s", cache_group) # Hitting cachegroup POST method response: tuple[JSONData, requests.Response] = to_session.create_cachegroups(data=cache_group) resp_obj = check_template_data(response, "cachegroup") - return resp_obj + yield resp_obj + cachegroup_id = resp_obj.get("id") + msg = to_session.delete_cachegroups(cache_group_id=cachegroup_id) + logger.info("Deleting cachegroup data... %s", msg) + if msg is None: + logger.error("Cachegroup returned by Traffic Ops is missing an 'id' property") + pytest.fail("Response from delete request is empty, Failing test_case") -@pytest.fixture() -def parameter_post_data(to_session: TOSession, request_template_data: list[JSONData] +@pytest.fixture(name="parameter_post_data") +def parameter_data_post(to_session: TOSession, request_template_data: list[JSONData] ) -> dict[str, object]: """ PyTest Fixture to create POST data for parameters endpoint. @@ -556,11 +583,17 @@ def parameter_post_data(to_session: TOSession, request_template_data: list[JSOND # Hitting cdns POST methed response: tuple[JSONData, requests.Response] = to_session.create_parameter(data=parameter) resp_obj = check_template_data(response, "parameter") - return resp_obj + yield resp_obj + parameter_id = resp_obj.get("id") + msg = to_session.delete_parameter(parameter_id=parameter_id) + logger.info("Deleting parameter data... %s", msg) + if msg is None: + logger.error("Parameter returned by Traffic Ops is missing an 'id' property") + pytest.fail("Response from delete request is empty, Failing test_case") -@pytest.fixture() -def role_post_data(to_session: TOSession, request_template_data: list[JSONData] +@pytest.fixture(name="role_post_data") +def role_data_post(to_session: TOSession, request_template_data: list[JSONData] ) -> dict[str, object]: """ PyTest Fixture to create POST data for roles endpoint. @@ -589,7 +622,13 @@ def role_post_data(to_session: TOSession, request_template_data: list[JSONData] # Hitting roles POST methed response: tuple[JSONData, requests.Response] = to_session.create_role(data=role) resp_obj = check_template_data(response, "role") - return resp_obj + yield resp_obj + role_name = resp_obj.get("name") + msg = to_session.delete_role(query_params={"name": role_name}) + logger.info("Deleting role data... %s", msg) + if msg is None: + logger.error("Role returned by Traffic Ops is missing an 'id' property") + pytest.fail("Response from delete request is empty, Failing test_case") @pytest.fixture(name="profile_post_data") @@ -620,12 +659,18 @@ def profile_data_post(to_session: TOSession, request_template_data: list[JSONDat # Hitting profile POST method response: tuple[JSONData, requests.Response] = to_session.create_profile(data=profile) resp_obj = check_template_data(response, "profile") - return resp_obj + yield resp_obj + profile_id = resp_obj.get("id") + msg = to_session.delete_profile_by_id(profile_id=profile_id) + logger.info("Deleting profile data... %s", msg) + if msg is None: + logger.error("Profile returned by Traffic Ops is missing an 'id' property") + pytest.fail("Response from delete request is empty, Failing test_case") @pytest.fixture(name="tenant_post_data") -def tenant_data_post(to_session: TOSession, request_template_data: list[JSONData] - ) -> dict[str, object]: +def tenant_data_post(to_session: TOSession, request_template_data: list[JSONData], + pytestconfig: pytest.Config) -> dict[str, object]: """ PyTest Fixture to create POST data for tenants endpoint. :param to_session: Fixture to get Traffic Ops session. @@ -637,23 +682,33 @@ def tenant_data_post(to_session: TOSession, request_template_data: list[JSONData # Return new post data and post response from tenants POST request randstr = str(randint(0, 1000)) - try: - name = tenant["name"] - if not isinstance(name, str): - raise TypeError(f"name must be str, not '{type(name)}'") - tenant["name"] = name[:4] + randstr - except KeyError as e: - raise TypeError(f"missing tenant property '{e.args[0]}'") from e + name = pytestconfig.cache.get("tenantName", default=None) + if name: + tenant["name"] = name + else: + try: + name = tenant["name"] + if not isinstance(name, str): + raise TypeError(f"name must be str, not '{type(name)}'") + tenant["name"] = name[:4] + randstr + except KeyError as e: + raise TypeError(f"missing tenant property '{e.args[0]}'") from e logger.info("New tenant data to hit POST method %s", tenant) # Hitting tenants POST methed response: tuple[JSONData, requests.Response] = to_session.create_tenant(data=tenant) resp_obj = check_template_data(response, "tenant") - return resp_obj + yield resp_obj + tenant_id = resp_obj.get("id") + msg = to_session.delete_tenant(tenant_id=tenant_id) + logger.info("Deleting tenant data... %s", msg) + if msg is None: + logger.error("Tenant returned by Traffic Ops is missing an 'id' property") + pytest.fail("Response from delete request is empty, Failing test_case") -@pytest.fixture() -def server_capabilities_post_data(to_session: TOSession, request_template_data: list[JSONData] +@pytest.fixture(name="server_capabilities_post_data") +def server_capabilities_data_post(to_session: TOSession, request_template_data: list[JSONData] ) -> dict[str, object]: """ PyTest Fixture to create POST data for server_capabilities endpoint. @@ -676,12 +731,18 @@ def server_capabilities_post_data(to_session: TOSession, request_template_data: except KeyError as e: raise TypeError(f"missing server_capabilities property '{e.args[0]}'") from e - logger.info("New server_capabilities data to hit POST method %s", request_template_data) + logger.info("New server_capabilities data to hit POST method %s", server_capabilities) # Hitting server_capabilities POST method response: tuple[ JSONData, requests.Response] = to_session.create_server_capabilities(data=server_capabilities) resp_obj = check_template_data(response, "server_capabilities") - return resp_obj + yield resp_obj + server_capability_name = resp_obj.get("name") + msg = to_session.delete_server_capabilities(query_params={"name": server_capability_name}) + logger.info("Deleting server_capabilities data %s", msg) + if msg is None: + logger.error("server_capabilities returned by Traffic Ops is missing an 'id' property") + pytest.fail("Response from delete request is empty, Failing test_server_capabilities_contract") @pytest.fixture(name="division_post_data") @@ -707,11 +768,17 @@ def division_data_post(to_session: TOSession, request_template_data: list[JSONDa except KeyError as e: raise TypeError(f"missing Parameter property '{e.args[0]}'") from e - logger.info("New division data to hit POST method %s", request_template_data) + logger.info("New division data to hit POST method %s", division) # Hitting division POST methed response: tuple[JSONData, requests.Response] = to_session.create_division(data=division) resp_obj = check_template_data(response, "divisions") - return resp_obj + yield resp_obj + division_id = resp_obj.get("id") + msg = to_session.delete_division(division_id=division_id) + logger.info("Deleting division data... %s", msg) + if msg is None: + logger.error("Division returned by Traffic Ops is missing an 'id' property") + pytest.fail("Response from delete request is empty, Failing test_case") @pytest.fixture(name="region_post_data") @@ -741,11 +808,17 @@ def region_data_post(to_session: TOSession, request_template_data: list[JSONData region["division"] = division_post_data["id"] region["divisionName"] = division_post_data["name"] - logger.info("New region data to hit POST method %s", request_template_data) + logger.info("New region data to hit POST method %s", region) # Hitting region POST method response: tuple[JSONData, requests.Response] = to_session.create_region(data=region) resp_obj = check_template_data(response, "regions") - return resp_obj + yield resp_obj + region_name = resp_obj.get("name") + msg = to_session.delete_region(query_params={"name": region_name}) + logger.info("Deleting region data... %s", msg) + if msg is None: + logger.error("Region returned by Traffic Ops is missing an 'id' property") + pytest.fail("Response from delete request is empty, Failing test_case") @pytest.fixture(name="phys_locations_post_data") @@ -782,18 +855,25 @@ def phys_locations_data_post(to_session: TOSession, request_template_data: list[ raise TypeError("malformed API response; 'id' property not a integer") phys_locations["regionId"] = region_id - logger.info("New Phys_locations data to hit POST method %s", request_template_data) + logger.info("New Phys_locations data to hit POST method %s", phys_locations) # Hitting region POST method response: tuple[JSONData, requests.Response] = to_session.create_physical_locations( data=phys_locations) resp_obj = check_template_data(response, "phys_locations") - return resp_obj - - -@pytest.fixture() -def server_post_data(to_session: TOSession, request_template_data: list[JSONData], - cdn_post_data: dict[str, object], - phys_locations_post_data: dict[str, object])-> dict[str, object]: + yield resp_obj + phys_location_id = resp_obj.get("id") + msg = to_session.delete_physical_location(physical_location_id=phys_location_id) + logger.info("Deleting physical locations data... %s", msg) + if msg is None: + logger.error("Physical location returned by Traffic Ops is missing an 'id' property") + pytest.fail("Response from delete request is empty, Failing test_case") + + +@pytest.fixture(name="server_post_data") +def server_data_post(to_session: TOSession, request_template_data: list[JSONData], + profile_post_data: dict[str, object], cache_group_post_data: dict[str, object], + status_post_data: dict[str, object], phys_locations_post_data: dict[str, object], + pytestconfig: pytest.Config)-> dict[str, object]: """ PyTest Fixture to create POST data for server endpoint. @@ -803,7 +883,6 @@ def server_post_data(to_session: TOSession, request_template_data: list[JSONData :returns: Sample POST data and the actual API response. """ server = check_template_data(request_template_data["servers"], "servers") - randstr = str(randint(0, 1000)) # Check if type already exists, otherwise create it type_data = check_template_data(request_template_data["types"], "types") @@ -811,30 +890,19 @@ def server_post_data(to_session: TOSession, request_template_data: list[JSONData {"useInTable": "server"}) type_id = type_object["id"] server["typeId"] = type_id + pytestconfig.cache.set("typeId", type_id) - # Check if cachegroup with type already exists, otherwise create it - cache_group_data = check_template_data(request_template_data["cachegroup"], "cachegroup") - cache_group_object = create_or_get_existing(to_session, "cachegroups", "cachegroups", - cache_group_data, {"typeId": type_id}) - server["cachegroupId"]= cache_group_object["id"] + server["cachegroupId"]= cache_group_post_data["id"] # Check if cdn already exists, otherwise create it - server["cdnId"] = cdn_post_data["id"] - server["domainName"] = cdn_post_data["domainName"] + server["cdnId"] = profile_post_data["cdn"] + server["domainName"] = pytestconfig.cache.get("cdnDomainName", default=None) # Check if profile with cdn already exists, otherwise create it - profile_data = check_template_data(request_template_data["profiles"], "profiles") - profile_data["cdn"] = cdn_post_data["id"] - name = profile_data["name"] - profile_data["name"] = name[:4] + randstr - profile_object = create_if_not_exists(to_session, "profile", profile_data) - server["profileNames"] = [profile_object["name"]] + server["profileNames"] = [profile_post_data["name"]] # Check if status already exists, otherwise create it - status_data = check_template_data(request_template_data["status"], "status") - status_object = create_or_get_existing(to_session, "statuses", "statuses", - status_data, {"name": "REPORTED"}) - server["statusId"] = status_object["id"] + server["statusId"] = status_post_data["id"] # Check if physical location with region already exists, otherwise create it physical_location_id = phys_locations_post_data["id"] @@ -846,13 +914,19 @@ def server_post_data(to_session: TOSession, request_template_data: list[JSONData # Hitting server POST method response: tuple[JSONData, requests.Response] = to_session.create_server(data=server) resp_obj = check_template_data(response, "server") - return [resp_obj, profile_object["id"]] + yield resp_obj + server_id = resp_obj.get("id") + msg = to_session.delete_server_by_id(server_id=server_id) + logger.info("Deleting servers data... %s", msg) + if msg is None: + logger.error("Server returned by Traffic Ops is missing an 'id' property") + pytest.fail("Response from delete request is empty, Failing test_case") @pytest.fixture(name="delivery_services_post_data") def delivery_services_data_post(to_session: TOSession, request_template_data: list[JSONData], - profile_post_data: dict[str, object] - ) -> dict[str, object]: + tenant_post_data: dict[str, object], profile_post_data: dict[str, object], + pytestconfig: pytest.Config) -> dict[str, object]: """ PyTest Fixture to create POST data for server endpoint. :param to_session: Fixture to get Traffic Ops session. @@ -878,10 +952,8 @@ def delivery_services_data_post(to_session: TOSession, request_template_data: li delivery_services["cdnId"] = profile_post_data["cdn"] # Check if tenant already exists, otherwise create it - tenant_data = check_template_data(request_template_data["tenants"], "tenants") - tenant_object = create_or_get_existing(to_session, "tenants", "tenant", - tenant_data, {"name": "root"}) - delivery_services["tenantId"] = tenant_object["id"] + pytestconfig.cache.set("tenantName", "root") + delivery_services["tenantId"] = tenant_post_data["id"] # Check if type already exists, otherwise create it type_data = {"name": "HTTP", "useInTable":"deliveryservice"} @@ -896,11 +968,17 @@ def delivery_services_data_post(to_session: TOSession, request_template_data: li response: tuple[JSONData, requests.Response] = to_session.create_deliveryservice( data=delivery_services) resp_obj = check_template_data(response[0], "delivery_services") - return resp_obj + yield resp_obj + delivery_service_id = resp_obj.get("id") + msg = to_session.delete_deliveryservice_by_id(delivery_service_id=delivery_service_id) + logger.info("Deleting delivery service data... %s", msg) + if msg is None: + logger.error("delivery service returned by Traffic Ops is missing an 'id' property") + pytest.fail("Response from delete request is empty, Failing test_case") -@pytest.fixture() -def origin_post_data(to_session: TOSession, request_template_data: list[JSONData], +@pytest.fixture(name="origin_post_data") +def origin_data_post(to_session: TOSession, request_template_data: list[JSONData], delivery_services_post_data: dict[str, object], tenant_post_data: dict[str, object] ) -> dict[str, object]: """ @@ -936,11 +1014,17 @@ def origin_post_data(to_session: TOSession, request_template_data: list[JSONData # Hitting origins POST method response: tuple[JSONData, requests.Response] = to_session.create_origins(data=origin) resp_obj = check_template_data(response, "origins") - return resp_obj + yield resp_obj + origin_id = resp_obj.get("id") + msg = to_session.delete_origins(query_params={"id": origin_id}) + logger.info("Deleting origin data... %s", msg) + if msg is None: + logger.error("Origin returned by Traffic Ops is missing an 'id' property") + pytest.fail("Response from delete request is empty, Failing test_case") -@pytest.fixture() -def status_post_data(to_session: TOSession, request_template_data: list[JSONData] +@pytest.fixture(name="status_post_data") +def status_data_post(to_session: TOSession, request_template_data: list[JSONData] ) -> dict[str, object]: """ PyTest Fixture to create POST data for statuses endpoint. @@ -965,7 +1049,14 @@ def status_post_data(to_session: TOSession, request_template_data: list[JSONData # Hitting statuses POST methed response: tuple[JSONData, requests.Response] = to_session.create_statuses(data=status) resp_obj = check_template_data(response, "statuses") - return resp_obj + yield resp_obj + status_id = resp_obj.get("id") + msg = to_session.delete_status_by_id(status_id=status_id) + logger.info("Deleting status data... %s", msg) + if msg is None: + logger.error("Status returned by Traffic Ops is missing an 'id' property") + pytest.fail("Response from delete request is empty, Failing test_case") + @pytest.fixture(name="asn_post_data") def asn_data_post(to_session: TOSession, request_template_data: list[JSONData], @@ -989,7 +1080,45 @@ def asn_data_post(to_session: TOSession, request_template_data: list[JSONData], # Hitting asns POST method response: tuple[JSONData, requests.Response] = to_session.create_asn(data=asn) resp_obj = check_template_data(response, "asn") - return resp_obj + yield resp_obj + asn_id = resp_obj.get("id") + msg = to_session.delete_asn(query_params={"id": asn_id}) + logger.info("Deleting asn data... %s", msg) + if msg is None: + logger.error("asn returned by Traffic Ops is missing an 'id' property") + pytest.fail("Response from delete request is empty, Failing test_case") + + +@pytest.fixture(name="job_post_data") +def job_data_post(to_session: TOSession, request_template_data: list[JSONData], + delivery_services_post_data: dict[str, object], + ) -> dict[str, object]: + """ + PyTest Fixture to create POST data for jobss endpoint. + :param to_session: Fixture to get Traffic Ops session. + :param request_template_data: Fixture to get job data from a prerequisites file. + :returns: Sample POST data and the actual API response. + """ + job = check_template_data(request_template_data["jobs"], "jobs") + + # Check if delivery_service already exists, otherwise create it + delivery_services_name = delivery_services_post_data["xmlId"] + if not isinstance(delivery_services_name, str): + raise TypeError("malformed API response; 'displayName' property not a string") + job["deliveryService"] = delivery_services_name + + logger.info("New job data to hit POST method %s", job) + # Hitting jobs POST method + response: tuple[JSONData, requests.Response] = to_session.create_job(data=job) + resp_obj = check_template_data(response, "jobs") + yield resp_obj + job_id = resp_obj.get("id") + msg = to_session.delete_job(query_params={"id": job_id}) + logger.info("Deleting job data... %s", msg) + if msg is None: + logger.error("job returned by Traffic Ops is missing an 'id' property") + pytest.fail("Response from delete request is empty, Failing test_case") + @pytest.fixture(name="coordinate_post_data") def coordinate_data_post(to_session: TOSession, request_template_data: list[JSONData] @@ -1017,4 +1146,10 @@ def coordinate_data_post(to_session: TOSession, request_template_data: list[JSON # Hitting coordinates POST methed response: tuple[JSONData, requests.Response] = to_session.create_coordinates(data=coordinate) resp_obj = check_template_data(response, "coordinate") - return resp_obj + yield resp_obj + coordinate_id = resp_obj.get("id") + msg = to_session.delete_coordinates(query_params={"id": coordinate_id}) + logger.info("Deleting Coordinate data... %s", msg) + if msg is None: + logger.error("coordinate returned by Traffic Ops is missing an 'id' property") + pytest.fail("Response from delete request is empty, Failing test_case") diff --git a/traffic_ops/testing/api_contract/v4/data/request_template.json b/traffic_ops/testing/api_contract/v4/data/request_template.json index 94ebcb03ff..f1b6dd5d2b 100644 --- a/traffic_ops/testing/api_contract/v4/data/request_template.json +++ b/traffic_ops/testing/api_contract/v4/data/request_template.json @@ -220,6 +220,15 @@ "cachegroupId": 10 } ], + "jobs": [ + { + "deliveryService": "test", + "invalidationType": "REFRESH", + "regex": "/.+", + "startTime": "2030-11-09T01:02:03Z", + "ttlHours": 72 + } + ], "coordinates": [ { "name": "test", diff --git a/traffic_ops/testing/api_contract/v4/data/response_template.json b/traffic_ops/testing/api_contract/v4/data/response_template.json index 5f25791443..c99acfc57b 100644 --- a/traffic_ops/testing/api_contract/v4/data/response_template.json +++ b/traffic_ops/testing/api_contract/v4/data/response_template.json @@ -1123,6 +1123,41 @@ } } }, + "jobs": { + "type": "object", + "required": [ + "id", + "assetUrl", + "createdBy", + "deliveryService", + "ttlHours", + "invalidationType", + "startTime" + ], + "properties": { + "id": { + "type": "integer" + }, + "assetUrl": { + "type": "string" + }, + "createdBy": { + "type": "string" + }, + "deliveryService": { + "type": "string" + }, + "ttlHours": { + "type": "integer" + }, + "invalidationType": { + "type": "string" + }, + "startTime": { + "type": "string" + } + } + }, "coordinates": { "type": "object", "required": [ diff --git a/traffic_ops/testing/api_contract/v4/test_asns.py b/traffic_ops/testing/api_contract/v4/test_asns.py index 9a41adaa5e..52969b13f7 100644 --- a/traffic_ops/testing/api_contract/v4/test_asns.py +++ b/traffic_ops/testing/api_contract/v4/test_asns.py @@ -73,14 +73,3 @@ def test_asn_contract(to_session: TOSession, except IndexError: logger.error("Either prerequisite data or API response was malformed") pytest.fail("API contract test failed for asns endpoint: API response was malformed") - finally: - # Delete asn after test execution to avoid redundancy. - asn_id = asn_post_data.get("id") - if to_session.delete_asn(query_params={"id": asn_id}) is None: - logger.error("asn returned by Traffic Ops is missing an 'id' property") - pytest.fail("Response from delete request is empty, Failing test_asn_contract") - - cachegroup_id = asn_post_data.get("cachegroupId") - if to_session.delete_cachegroups(cache_group_id=cachegroup_id) is None: - logger.error("Cachegroup returned by Traffic Ops is missing an 'id' property") - pytest.fail("Response from delete request is empty, Failing test_asn_contract") diff --git a/traffic_ops/testing/api_contract/v4/test_cachegroups.py b/traffic_ops/testing/api_contract/v4/test_cachegroups.py index d4cf6ceadb..646bfe6731 100644 --- a/traffic_ops/testing/api_contract/v4/test_cachegroups.py +++ b/traffic_ops/testing/api_contract/v4/test_cachegroups.py @@ -75,9 +75,3 @@ def test_cache_group_contract(to_session: TOSession, except IndexError: logger.error("Either prerequisite data or API response was malformed") pytest.fail("API contract test failed for cachegroup endpoint: API response was malformed") - finally: - # Delete Cache group after test execution to avoid redundancy. - cache_group_id = cache_group_post_data.get("id") - if to_session.delete_cachegroups(cache_group_id=cache_group_id) is None: - logger.error("Cachegroup returned by Traffic Ops is missing an 'id' property") - pytest.fail("Response from delete request is empty, Failing test_cachegroup_contract") diff --git a/traffic_ops/testing/api_contract/v4/test_cdns.py b/traffic_ops/testing/api_contract/v4/test_cdns.py index 79691777ec..83cb844b79 100644 --- a/traffic_ops/testing/api_contract/v4/test_cdns.py +++ b/traffic_ops/testing/api_contract/v4/test_cdns.py @@ -74,9 +74,3 @@ def test_cdn_contract( except IndexError: logger.error("Either prerequisite data or API response was malformed") pytest.fail("API contract test failed for cdn endpoint: API response was malformed") - finally: - # Delete CDN after test execution to avoid redundancy. - cdn_id = cdn_post_data.get("id") - if to_session.delete_cdn_by_id(cdn_id=cdn_id) is None: - logger.error("CDN returned by Traffic Ops is missing an 'id' property") - pytest.fail("Response from delete request is empty, Failing test_get_cdn") diff --git a/traffic_ops/testing/api_contract/v4/test_coordinates.py b/traffic_ops/testing/api_contract/v4/test_coordinates.py index 799573fb81..394da23929 100644 --- a/traffic_ops/testing/api_contract/v4/test_coordinates.py +++ b/traffic_ops/testing/api_contract/v4/test_coordinates.py @@ -76,9 +76,3 @@ def test_coordinate_contract(to_session: TOSession, except IndexError: logger.error("Either prerequisite data or API response was malformed") pytest.fail("API contract test failed for coordinates endpoint: API response was malformed") - finally: - # Delete coordinate after test execution to avoid redundancy. - coordinate_id = coordinate_post_data.get("id") - if to_session.delete_coordinates(query_params={"id": coordinate_id}) is None: - logger.error("coordinate returned by Traffic Ops is missing a 'id' property") - pytest.fail("Response from delete request is empty, Failing test_coordinates_contract") diff --git a/traffic_ops/testing/api_contract/v4/test_delivery_services.py b/traffic_ops/testing/api_contract/v4/test_delivery_services.py index 41e3963b5b..9311ec0583 100644 --- a/traffic_ops/testing/api_contract/v4/test_delivery_services.py +++ b/traffic_ops/testing/api_contract/v4/test_delivery_services.py @@ -74,19 +74,3 @@ def test_delivery_services_contract(to_session: TOSession, except IndexError: logger.error("Either prerequisite data or API response was malformed") pytest.fail("API contract test failed for delivery_services endpoint: API response was malformed") - finally: - # Delete delivery_services after test execution to avoid redundancy. - delivery_service_id = delivery_services_post_data.get("id") - if to_session.delete_deliveryservice_by_id(delivery_service_id=delivery_service_id) is None: - logger.error("delivery_services returned by Traffic Ops is missing an 'id' property") - pytest.fail("Response from delete request is empty, Failing test_delivery_services_contract") - - profile_id = delivery_services_post_data.get("profileId") - if to_session.delete_profile_by_id(profile_id=profile_id) is None: - logger.error("profile returned by Traffic Ops is missing an 'id' property") - pytest.fail("Response from delete request is empty, Failing test_delivery_services_contract") - - cdn_id = delivery_services_post_data.get("cdnId") - if to_session.delete_cdn_by_id(cdn_id=cdn_id) is None: - logger.error("cdn returned by Traffic Ops is missing an 'id' property") - pytest.fail("Response from delete request is empty, Failing test_delivery_services_contract") diff --git a/traffic_ops/testing/api_contract/v4/test_divisions.py b/traffic_ops/testing/api_contract/v4/test_divisions.py index 548a093222..200e3d94e9 100644 --- a/traffic_ops/testing/api_contract/v4/test_divisions.py +++ b/traffic_ops/testing/api_contract/v4/test_divisions.py @@ -73,9 +73,3 @@ def test_division_contract(to_session: TOSession, except IndexError: logger.error("Either prerequisite data or API response was malformed") pytest.fail("Failed due to malformation") - finally: - # Delete division after test execution to avoid redundancy. - division_id = division_post_data.get("id") - if to_session.delete_division(division_id=division_id) is None: - logger.error("Division returned by Traffic Ops is missing an 'id' property") - pytest.fail("Response from delete request is empty, Failing test_get_division") diff --git a/traffic_ops/testing/api_contract/v4/test_jobs.py b/traffic_ops/testing/api_contract/v4/test_jobs.py new file mode 100644 index 0000000000..ccc22bfb73 --- /dev/null +++ b/traffic_ops/testing/api_contract/v4/test_jobs.py @@ -0,0 +1,76 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +"""API Contract Test Case for jobs endpoint.""" +import logging +from typing import Union + +import pytest +import requests +from jsonschema import validate + +from trafficops.tosession import TOSession + +# Create and configure logger +logger = logging.getLogger() + +Primitive = Union[bool, int, float, str, None] + +def test_job_contract(to_session: TOSession, + response_template_data: dict[str, Union[Primitive, + list[Union[Primitive, dict[str, object], list[object]]], + dict[object, object]]], job_post_data: dict[str, object]) -> None: + """ + Test step to validate keys, values and data types from jobs endpoint + response. + :param to_session: Fixture to get Traffic Ops session. + :param response_template_data: Fixture to get response template data from a prerequisites file. + :param job_post_data: Fixture to get sample job data and actual job response. + """ + # validate job keys from jobs get response + logger.info("Accessing /jobs endpoint through Traffic ops session.") + + job_id = job_post_data.get("id") + if not isinstance(job_id, int): + raise TypeError("malformed job in prerequisite data; 'id' not a integer") + + job_get_response: tuple[ + Union[dict[str, object], list[Union[dict[str, object], list[object], Primitive]], Primitive], + requests.Response + ] = to_session.get_jobs(query_params={"id": job_id}) + try: + job_data = job_get_response[0] + if not isinstance(job_data, list): + raise TypeError("malformed API response; 'response' property not an array") + + first_job = job_data[0] + if not isinstance(first_job, dict): + raise TypeError("malformed API response; first job in response is not an dict") + logger.info("job Api get response %s", first_job) + + job_response_template = response_template_data.get("jobs") + if not isinstance(job_response_template, dict): + raise TypeError( + f"job response template data must be a dict, not '{type(job_response_template)}'") + + # validate job values from prereq data in jobs get response. + keys = ["deliveryService", "invalidationType", "startTime", "ttlHours"] + prereq_values = [job_post_data[key] for key in keys] + get_values = [first_job[key] for key in keys] + + assert validate(instance=first_job, schema=job_response_template) is None + assert get_values == prereq_values + except IndexError: + logger.error("Either prerequisite data or API response was malformed") + pytest.fail("API contract test failed for cdn endpoint: API response was malformed") diff --git a/traffic_ops/testing/api_contract/v4/test_origins.py b/traffic_ops/testing/api_contract/v4/test_origins.py index 0943b24b79..14aea804ea 100644 --- a/traffic_ops/testing/api_contract/v4/test_origins.py +++ b/traffic_ops/testing/api_contract/v4/test_origins.py @@ -75,14 +75,3 @@ def test_origin_contract( except IndexError: logger.error("Either prerequisite data or API response was malformed") pytest.fail("API contract test failed for origin endpoint: API response was malformed") - finally: - # Delete origin after test execution to avoid redundancy. - origin_id = origin_post_data.get("id") - if to_session.delete_origins(query_params={"id": origin_id}) is None: - logger.error("Origin returned by Traffic Ops is missing an 'id' property") - pytest.fail("Response from delete request is empty, Failing test_origin_contract") - - delivery_service_id = origin_post_data.get("deliveryServiceId") - if to_session.delete_deliveryservice_by_id(delivery_service_id=delivery_service_id) is None: - logger.error("Delivery service returned by Traffic Ops is missing an 'id' property") - pytest.fail("Response from delete request is empty, Failing test_origin_contract") diff --git a/traffic_ops/testing/api_contract/v4/test_parameters.py b/traffic_ops/testing/api_contract/v4/test_parameters.py index 2cff807ed8..51205ad8d9 100644 --- a/traffic_ops/testing/api_contract/v4/test_parameters.py +++ b/traffic_ops/testing/api_contract/v4/test_parameters.py @@ -76,9 +76,3 @@ def test_parameter_contract(to_session: TOSession, except IndexError: logger.error("Either prerequisite data or API response was malformed") pytest.fail("API contract test failed for cdn endpoint: API response was malformed") - finally: - # Delete Parameter after test execution to avoid redundancy. - parameter_id = parameter_post_data.get("id") - if to_session.delete_parameter(parameter_id=parameter_id) is None: - logger.error("Parameter returned by Traffic Ops is missing an 'id' property") - pytest.fail("Response from delete request is empty, Failing test_parameter_contract") diff --git a/traffic_ops/testing/api_contract/v4/test_phys_locations.py b/traffic_ops/testing/api_contract/v4/test_phys_locations.py index ab32a602c9..9a52dfc95c 100644 --- a/traffic_ops/testing/api_contract/v4/test_phys_locations.py +++ b/traffic_ops/testing/api_contract/v4/test_phys_locations.py @@ -77,14 +77,3 @@ def test_phys_locations_contract(to_session: TOSession, except IndexError: logger.error("Either prerequisite data or API response was malformed") pytest.fail("API contract test failed for phys_locations endpoint: API response was malformed") - finally: - # Delete phys_location after test execution to avoid redundancy. - physical_location_id = phys_locations_post_data["id"] - if to_session.delete_physical_location(physical_location_id=physical_location_id) is None: - logger.error("phys_location returned by Traffic Ops is missing an 'id' property") - pytest.fail("Response from delete request is empty, Failing test_get_phys_location") - - region_id = phys_locations_post_data["regionId"] - if to_session.delete_region(query_params={"id": region_id}) is None: - logger.error("Region returned by Traffic Ops is missing an 'id' property") - pytest.fail("Response from delete request is empty, Failing test_get_phys_location") diff --git a/traffic_ops/testing/api_contract/v4/test_profiles.py b/traffic_ops/testing/api_contract/v4/test_profiles.py index 6745bcf8d0..8533fb4aba 100644 --- a/traffic_ops/testing/api_contract/v4/test_profiles.py +++ b/traffic_ops/testing/api_contract/v4/test_profiles.py @@ -73,14 +73,3 @@ def test_profile_contract(to_session: TOSession, except IndexError: logger.error("Either prerequisite data or API response was malformed") pytest.fail("API contract test failed for cdn endpoint: API response was malformed") - finally: - # Delete Profile after test execution to avoid redundancy. - profile_id = profile_post_data.get("id") - if to_session.delete_profile_by_id(profile_id=profile_id) is None: - logger.error("Profile returned by Traffic Ops is missing an 'id' property") - pytest.fail("Response from delete request is empty, Failing test_profile_contract") - - cdn_id = profile_post_data.get("cdn") - if to_session.delete_cdn_by_id(cdn_id=cdn_id) is None: - logger.error("Cdn returned by Traffic Ops is missing an 'id' property") - pytest.fail("Response from delete request is empty, Failing test_profile_contract") diff --git a/traffic_ops/testing/api_contract/v4/test_regions.py b/traffic_ops/testing/api_contract/v4/test_regions.py index 49fd985bd9..3b266a66a2 100644 --- a/traffic_ops/testing/api_contract/v4/test_regions.py +++ b/traffic_ops/testing/api_contract/v4/test_regions.py @@ -76,14 +76,3 @@ def test_region_contract(to_session: TOSession, except IndexError: logger.error("Either prerequisite data or API response was malformed") pytest.fail("API contract test failed for regions endpoint: API response was malformed") - finally: - # Delete region after test execution to avoid redundancy. - region_name = region_post_data.get("name") - if to_session.delete_region(query_params={"name": region_name}) is None: - logger.error("region returned by Traffic Ops is missing a 'name' property") - pytest.fail("Response from delete request is empty, Failing test_region_contract") - - division_id = region_post_data.get("division") - if to_session.delete_division(division_id=division_id) is None: - logger.error("division returned by Traffic Ops is missing a 'name' property") - pytest.fail("Response from delete request is empty, Failing test_region_contract") diff --git a/traffic_ops/testing/api_contract/v4/test_roles.py b/traffic_ops/testing/api_contract/v4/test_roles.py index 16ba345e16..d476d6fe20 100644 --- a/traffic_ops/testing/api_contract/v4/test_roles.py +++ b/traffic_ops/testing/api_contract/v4/test_roles.py @@ -75,9 +75,3 @@ def test_role_contract(to_session: TOSession, except IndexError: logger.error("Either prerequisite data or API response was malformed") pytest.fail("API contract test failed for roles endpoint: API response was malformed") - finally: - # Delete Role after test execution to avoid redundancy. - role_name = role_post_data.get("name") - if to_session.delete_role(query_params={"name": role_name}) is None: - logger.error("Role returned by Traffic Ops is missing an 'name' property") - pytest.fail("Response from delete request is empty, Failing test_role_contract") diff --git a/traffic_ops/testing/api_contract/v4/test_server_capabilities.py b/traffic_ops/testing/api_contract/v4/test_server_capabilities.py index adaa064c09..2f30df03b1 100644 --- a/traffic_ops/testing/api_contract/v4/test_server_capabilities.py +++ b/traffic_ops/testing/api_contract/v4/test_server_capabilities.py @@ -73,9 +73,3 @@ def test_server_capabilities_contract(to_session: TOSession, except IndexError: logger.error("Either prerequisite data or API response was malformed") pytest.fail("API contract test failed for server_capabilities: API response was malformed") - finally: - # Delete server_capabilities after test execution to avoid redundancy. - server_capability_name = server_capabilities_post_data.get("name") - if to_session.delete_server_capabilities(query_params={"name": server_capability_name}) is None: - logger.error("server_capabilities returned by Traffic Ops is missing an 'id' property") - pytest.fail("Response from delete request is empty, Failing test_server_capabilities_contract") diff --git a/traffic_ops/testing/api_contract/v4/test_servers.py b/traffic_ops/testing/api_contract/v4/test_servers.py index 51c0eed475..681ed9e5a3 100644 --- a/traffic_ops/testing/api_contract/v4/test_servers.py +++ b/traffic_ops/testing/api_contract/v4/test_servers.py @@ -27,11 +27,10 @@ Primitive = Union[bool, int, float, str, None] - def test_server_contract(to_session: TOSession, response_template_data: dict[str, Union[Primitive, list[Union[Primitive, dict[str, object], list[object]]], - dict[object, object]]], server_post_data: dict[str, object]) -> None: + dict[object, object]]], server_post_data: dict[str, object],request: pytest.FixtureRequest) -> None: """ Test step to validate keys, values and data types from servers endpoint response. @@ -41,8 +40,6 @@ def test_server_contract(to_session: TOSession, """ # validate server keys from server get response logger.info("Accessing /servers endpoint through Traffic ops session.") - profile_id = server_post_data[1] - server_post_data = server_post_data[0] server_id = server_post_data.get("id") if not isinstance(server_id, int): @@ -76,28 +73,3 @@ def test_server_contract(to_session: TOSession, except IndexError: logger.error("Either prerequisite data or API response was malformed") pytest.fail("API contract test failed for server endpoint: API response was malformed") - finally: - # Delete Server after test execution to avoid redundancy. - server_id = server_post_data.get("id") - if to_session.delete_server_by_id(server_id=server_id) is None: - logger.error("Server returned by Traffic Ops is missing an 'id' property") - pytest.fail("Response from delete request is empty, Failing test_server_contract") - - cachegroup_id = server_post_data.get("cachegroupId") - if to_session.delete_cachegroups(cache_group_id=cachegroup_id) is None: - logger.error("cachegroup returned by Traffic Ops is missing an 'id' property") - pytest.fail("Response from delete request is empty, Failing test_server_contract") - - if to_session.delete_profile_by_id(profile_id=profile_id) is None: - logger.error("Profile returned by Traffic Ops is missing an 'id' property") - pytest.fail("Response from delete request is empty, Failing test_server_contract") - - cdn_id = server_post_data.get("cdnId") - if to_session.delete_cdn_by_id(cdn_id=cdn_id) is None: - logger.error("Cdn returned by Traffic Ops is missing an 'id' property") - pytest.fail("Response from delete request is empty, Failing test_server_contract") - - phys_loc_id = server_post_data.get("physLocationId") - if to_session.delete_physical_location(physical_location_id=phys_loc_id) is None: - logger.error("Physical location returned by Traffic Ops is missing an 'id' property") - pytest.fail("Response from delete request is empty, Failing test_server_contract") diff --git a/traffic_ops/testing/api_contract/v4/test_statuses.py b/traffic_ops/testing/api_contract/v4/test_statuses.py index d12d0586f8..88934ec945 100644 --- a/traffic_ops/testing/api_contract/v4/test_statuses.py +++ b/traffic_ops/testing/api_contract/v4/test_statuses.py @@ -74,11 +74,3 @@ def test_status_contract( except IndexError: logger.error("Either prerequisite data or API response was malformed") pytest.fail("API contract test failed for status endpoint: API response was malformed") - finally: - # Delete Status after test execution to avoid redundancy. - try: - status_id = status_post_data["id"] - to_session.delete_status_by_id(status_id=status_id) - except IndexError: - logger.error("Status returned by Traffic Ops is missing an 'id' property") - pytest.fail("Response from delete request is empty, Failing test_get_status") diff --git a/traffic_ops/testing/api_contract/v4/test_tenants.py b/traffic_ops/testing/api_contract/v4/test_tenants.py index eaaae253ee..fbb2781f58 100644 --- a/traffic_ops/testing/api_contract/v4/test_tenants.py +++ b/traffic_ops/testing/api_contract/v4/test_tenants.py @@ -76,9 +76,3 @@ def test_tenant_contract(to_session: TOSession, except IndexError: logger.error("Either prerequisite data or API response was malformed") pytest.fail("API contract test failed for tenants endpoint: API response was malformed") - finally: - # Delete tenant after test execution to avoid redundancy. - tenant_id = tenant_post_data.get("id") - if to_session.delete_tenant(tenant_id=tenant_id) is None: - logger.error("Tenant returned by Traffic Ops is missing an 'id' property") - pytest.fail("Response from delete request is empty, Failing test_tenant_contract")