This is an automated email from the ASF dual-hosted git repository.

ericholguin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficcontrol.git


The following commit(s) were added to refs/heads/master by this push:
     new 44183093f4 Added Api contract tests for origins and delivery_services 
endpoints (#7529)
44183093f4 is described below

commit 44183093f436c0325e1e4d78e12f8b410cf5b96c
Author: Gokula Krishnan <[email protected]>
AuthorDate: Thu Jun 1 23:41:42 2023 +0530

    Added Api contract tests for origins and delivery_services endpoints (#7529)
    
    * Added Api contract tests for origins and delivery_services endpoints
    
    * Addressed review comments
    
    * updated code
    
    * modified code
    
    * Updated response template and added code to delete prerequisites data in 
required TCs
---
 traffic_ops/testing/api_contract/v4/conftest.py    | 156 +++++--
 .../api_contract/v4/data/request_template.json     |  83 +++-
 .../api_contract/v4/data/response_template.json    | 514 ++++++++++++++++++++-
 .../testing/api_contract/v4/test_cachegroups.py    |   8 +-
 traffic_ops/testing/api_contract/v4/test_cdns.py   |   6 +-
 .../api_contract/v4/test_delivery_services.py      |  92 ++++
 .../testing/api_contract/v4/test_divisions.py      |   8 +-
 .../testing/api_contract/v4/test_origins.py        |  88 ++++
 .../testing/api_contract/v4/test_parameters.py     |   8 +-
 .../testing/api_contract/v4/test_phys_locations.py |  13 +-
 .../testing/api_contract/v4/test_profiles.py       |  13 +-
 .../testing/api_contract/v4/test_regions.py        |  15 +-
 traffic_ops/testing/api_contract/v4/test_roles.py  |   8 +-
 .../api_contract/v4/test_server_capabilities.py    |   8 +-
 .../testing/api_contract/v4/test_servers.py        |  29 +-
 .../testing/api_contract/v4/test_tenants.py        |   8 +-
 16 files changed, 954 insertions(+), 103 deletions(-)

diff --git a/traffic_ops/testing/api_contract/v4/conftest.py 
b/traffic_ops/testing/api_contract/v4/conftest.py
index 4e61af218c..e42fa1ddd5 100644
--- a/traffic_ops/testing/api_contract/v4/conftest.py
+++ b/traffic_ops/testing/api_contract/v4/conftest.py
@@ -24,6 +24,7 @@ import os
 from random import randint
 from typing import Any, NamedTuple, Union, Optional, TypeAlias
 from urllib.parse import urlparse
+import munch
 
 import pytest
 import requests
@@ -362,7 +363,7 @@ def response_template_data(pytestconfig: pytest.Config
 
 def api_response_data(api_response: tuple[Union[Primitive, dict[str, object], 
list[
        Union[Primitive, dict[str, object], list[
-               object]]]], requests.Response]) -> dict[str, object]:
+               object]]]], requests.Response], create_check: bool) -> 
dict[str, object]:
        """
        Checks API get/post response.
        :param api_response: Raw api response.
@@ -371,14 +372,18 @@ def api_response_data(api_response: 
tuple[Union[Primitive, dict[str, object], li
        api_data = None
        if isinstance(api_response, tuple):
                api_response = api_response[0]
-               if not isinstance(api_response, list):
-                       raise ValueError("Malformed API response; 'response' 
property not an array")
+               if create_check and not isinstance(api_response, munch.Munch):
+                       raise ValueError("Malformed API response; 'response' 
property not an munch")
+               if not create_check and not isinstance(api_response, list):
+                       raise ValueError("Malformed API response; 'response' 
property not an list")
        else:
                raise ValueError("Invalid API response format")
 
        if api_response:
                try:
-                       api_data = api_response[0]
+                       api_data = api_response
+                       if not create_check:
+                               api_data = api_response[0]
                        if not isinstance(api_data, dict):
                                raise ValueError("Malformed API response; 
'response' property not a dict")
                except IndexError as e:
@@ -399,7 +404,7 @@ def get_existing_object(to_session: TOSession, object_type: 
str, query_params: O
        api_get_response: tuple[Union[dict[str, object], list[
                Union[dict[str, object], list[object], Primitive]], Primitive], 
requests.Response] = getattr(
                to_session, f"get_{object_type}")(query_params=query_params)
-       return api_response_data(api_get_response)
+       return api_response_data(api_get_response, create_check = False)
 
 
 def create_if_not_exists(to_session: TOSession, object_type: str,
@@ -414,7 +419,7 @@ def create_if_not_exists(to_session: TOSession, 
object_type: str,
        api_post_response: tuple[Union[dict[str, object], list[
                Union[dict[str, object], list[object], Primitive]], Primitive], 
requests.Response] = getattr(
                to_session, f"create_{object_type}")(data=data)
-       return api_response_data(api_post_response)
+       return api_response_data(api_post_response, create_check = True)
 
 
 def create_or_get_existing(to_session: TOSession, get_object_type: str, 
post_object_type: str, data:
@@ -451,8 +456,8 @@ def check_template_data(template_data: 
Union[list[JSONData], tuple[JSONData, req
        return endpoint
 
 
[email protected]()
-def cdn_post_data(to_session: TOSession, request_template_data: list[JSONData]
[email protected](name="cdn_post_data")
+def cdn_data_post(to_session: TOSession, request_template_data: list[JSONData]
                  ) -> dict[str, object]:
        """
        PyTest Fixture to create POST data for cdns endpoint.
@@ -587,9 +592,9 @@ def role_post_data(to_session: TOSession, 
request_template_data: list[JSONData]
        return resp_obj
 
 
[email protected]()
-def profile_post_data(to_session: TOSession, request_template_data: 
list[JSONData]
-                     ) -> dict[str, object]:
[email protected](name="profile_post_data")
+def profile_data_post(to_session: TOSession, request_template_data: 
list[JSONData],
+                     cdn_post_data:dict[str, object]) -> dict[str, object]:
        """
        PyTest Fixture to create POST data for profile endpoint.
 
@@ -609,9 +614,7 @@ def profile_post_data(to_session: TOSession, 
request_template_data: list[JSONDat
                raise TypeError(f"missing Profile property '{e.args[0]}'") from 
e
 
        # Check if cdn already exists, otherwise create it
-       cdn_data = check_template_data(request_template_data["cdns"], "cdns")
-       cdn_object = create_or_get_existing(to_session, "cdns", "cdn", cdn_data)
-       profile["cdn"] = cdn_object["id"]
+       profile["cdn"] = cdn_post_data["id"]
        logger.info("New profile data to hit POST method %s", profile)
 
        # Hitting profile POST method
@@ -620,8 +623,8 @@ def profile_post_data(to_session: TOSession, 
request_template_data: list[JSONDat
        return resp_obj
 
 
[email protected]()
-def tenant_post_data(to_session: TOSession, request_template_data: 
list[JSONData]
[email protected](name="tenant_post_data")
+def tenant_data_post(to_session: TOSession, request_template_data: 
list[JSONData]
                  ) -> dict[str, object]:
        """
        PyTest Fixture to create POST data for tenants endpoint.
@@ -681,8 +684,8 @@ def server_capabilities_post_data(to_session: TOSession, 
request_template_data:
        return resp_obj
 
 
[email protected]()
-def division_post_data(to_session: TOSession, request_template_data: 
list[JSONData]
[email protected](name="division_post_data")
+def division_data_post(to_session: TOSession, request_template_data: 
list[JSONData]
                  ) -> dict[str, object]:
        """
        PyTest Fixture to create POST data for divisions endpoint.
@@ -712,8 +715,8 @@ def division_post_data(to_session: TOSession, 
request_template_data: list[JSONDa
 
 
 @pytest.fixture(name="region_post_data")
-def region_data_post(to_session: TOSession, request_template_data: 
list[JSONData]
-                         ) -> dict[str, object]:
+def region_data_post(to_session: TOSession, request_template_data: 
list[JSONData],
+                         division_post_data: dict[str, object]) -> dict[str, 
object]:
        """
        PyTest Fixture to create POST data for region endpoint.
 
@@ -735,10 +738,8 @@ def region_data_post(to_session: TOSession, 
request_template_data: list[JSONData
                raise TypeError(f"missing Region property '{e.args[0]}'") from e
 
        # Check if division already exists, otherwise create it
-       division_data = check_template_data(request_template_data["divisions"], 
"divisions")
-       division_object = create_or_get_existing(to_session, "divisions", 
"division", division_data)
-       region["division"] = division_object["id"]
-       region["divisionName"] = division_object["name"]
+       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)
        # Hitting region POST method
@@ -791,7 +792,8 @@ def phys_locations_data_post(to_session: TOSession, 
request_template_data: list[
 
 @pytest.fixture()
 def server_post_data(to_session: TOSession, request_template_data: 
list[JSONData],
-                     phys_locations_post_data: dict[str, object]) -> dict[str, 
object]:
+               cdn_post_data: dict[str, object],
+               phys_locations_post_data: dict[str, object])-> dict[str, 
object]:
        """
        PyTest Fixture to create POST data for server endpoint.
 
@@ -801,6 +803,7 @@ 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")
@@ -816,15 +819,15 @@ def server_post_data(to_session: TOSession, 
request_template_data: list[JSONData
        server["cachegroupId"]= cache_group_object["id"]
 
        # Check if cdn already exists, otherwise create it
-       cdn_data = check_template_data(request_template_data["cdns"], "cdns")
-       cdn_object = create_or_get_existing(to_session, "cdns", "cdn", 
cdn_data, {"name": "CDN-in-a-Box"})
-       server["cdnId"] = cdn_object["id"]
-       server["domainName"] = cdn_object["domainName"]
+       server["cdnId"] = cdn_post_data["id"]
+       server["domainName"] = cdn_post_data["domainName"]
 
        # Check if profile with cdn already exists, otherwise create it
        profile_data = check_template_data(request_template_data["profiles"], 
"profiles")
-       profile_object = create_or_get_existing(to_session, "profiles", 
"profile", profile_data,
-                                        {"name": "test"})
+       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"]]
 
        # Check if status already exists, otherwise create it
@@ -843,8 +846,99 @@ 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"]]
+
+
[email protected](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]:
+       """
+       PyTest Fixture to create POST data for server endpoint.
+       :param to_session: Fixture to get Traffic Ops session.
+       :param request_template_data: Fixture to get profile data from a 
prerequisites file.
+       :returns: Sample POST data and the actual API response.
+       """
+       delivery_services = check_template_data(
+               request_template_data["delivery_services"], "delivery_services")
+
+       randstr = str(randint(0, 1000))
+       try:
+               xml_id = delivery_services["xmlId"]
+               if not isinstance(xml_id, str):
+                       raise TypeError(f"xmlId must be str, not 
'{type(xml_id)}'")
+               delivery_services["xmlId"] = xml_id[:4] + randstr
+       except KeyError as e:
+               raise TypeError(f"missing delivery_services property 
'{e.args[0]}'") from e
+
+       # Check if profile with cdn already exists, otherwise create it
+       delivery_services["profileId"] = profile_post_data["id"]
+
+       # Check if cdn already exists, otherwise create it
+       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"]
+
+       # Check if type already exists, otherwise create it
+       type_data = {"name": "HTTP", "useInTable":"deliveryservice"}
+       type_object = create_or_get_existing(to_session, "types", "type", 
type_data,
+                                     {"name": "HTTP", 
"useInTable":"deliveryservice"})
+       delivery_services["typeId"] = type_object["id"]
+       delivery_services["type"] = type_object["name"]
+
+
+       logger.info("New delivery_services data to hit POST method %s", 
delivery_services)
+       # Hitting delivery_services POST method
+       response: tuple[JSONData, requests.Response] = 
to_session.create_deliveryservice(
+               data=delivery_services)
+       resp_obj = check_template_data(response[0], "delivery_services")
        return resp_obj
 
+
[email protected]()
+def origin_post_data(to_session: TOSession, request_template_data: 
list[JSONData],
+                    delivery_services_post_data: dict[str, object], 
tenant_post_data: dict[str, object]
+                     ) -> dict[str, object]:
+       """
+       PyTest Fixture to create POST data for origins endpoint.
+       :param to_session: Fixture to get Traffic Ops session.
+       :param request_template_data: Fixture to get profile data from a 
prerequisites file.
+       :returns: Sample POST data and the actual API response.
+       """
+       origin = check_template_data(request_template_data["origins"], 
"origins")
+
+       randstr = str(randint(0, 1000))
+       try:
+               name = origin["name"]
+               if not isinstance(name, str):
+                       raise TypeError(f"name must be str, not '{type(name)}'")
+               origin["name"] = name[:4] + randstr
+       except KeyError as e:
+               raise TypeError(f"missing origin property '{e.args[0]}'") from e
+
+       # Check if delivery_service already exists, otherwise create it
+       delivery_services_id = delivery_services_post_data["id"]
+       if not isinstance(delivery_services_id, int):
+               raise TypeError("malformed API response; 'id' property not a 
integer")
+       origin["deliveryServiceId"] = delivery_services_id
+
+       # Check if tenant already exists, otherwise create it
+       tenant_id = tenant_post_data["id"]
+       if not isinstance(tenant_id, int):
+               raise TypeError("malformed API response; 'id' property not a 
integer")
+       origin["tenantId"] = tenant_id
+
+       logger.info("New origin data to hit POST method %s", origin)
+       # 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
+
+
 @pytest.fixture()
 def status_post_data(to_session: TOSession, request_template_data: 
list[JSONData]
                  ) -> dict[str, object]:
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 da10040eae..a54f115edd 100644
--- a/traffic_ops/testing/api_contract/v4/data/request_template.json
+++ b/traffic_ops/testing/api_contract/v4/data/request_template.json
@@ -76,7 +76,7 @@
        ],
        "regions": [
                {
-                       "name": "Manchester",
+                       "name": "test",
                        "division": "4",
                        "divisionName": "England"
                }
@@ -134,5 +134,84 @@
                        "typeId": 96,
                        "updPending": false
                }
+       ],
+       "delivery_services": [
+               {
+                       "active": false,
+                       "anonymousBlockingEnabled": false,
+                       "ccrDnsTtl": null,
+                       "cdnId": 2,
+                       "checkPath": null,
+                       "consistentHashRegex": null,
+                       "consistentHashQueryParams": [],
+                       "deepCachingType": "NEVER",
+                       "displayName": "test",
+                       "dnsBypassCname": null,
+                       "dnsBypassIp": null,
+                       "dnsBypassIp6": null,
+                       "dnsBypassTtl": null,
+                       "dscp": 0,
+                       "ecsEnabled": true,
+                       "edgeHeaderRewrite": null,
+                       "firstHeaderRewrite": null,
+                       "fqPacingRate": null,
+                       "geoLimit": 0,
+                       "geoLimitCountries": null,
+                       "geoLimitRedirectUrl": null,
+                       "geoProvider": 0,
+                       "globalMaxMbps": null,
+                       "globalMaxTps": null,
+                       "httpBypassFqdn": null,
+                       "infoUrl": null,
+                       "initialDispersion": 1,
+                       "innerHeaderRewrite": null,
+                       "ipv6RoutingEnabled": false,
+                       "lastHeaderRewrite": null,
+                       "logsEnabled": true,
+                       "longDesc": "A Delivery Service created expressly for 
API documentation examples",
+                       "maxDnsAnswers": null,
+                       "missLat": 0,
+                       "missLong": 0,
+                       "maxOriginConnections": 0,
+                       "maxRequestHeaderBytes": 131072,
+                       "midHeaderRewrite": null,
+                       "multiSiteOrigin": false,
+                       "orgServerFqdn": "http://origin.infra.ciab.test";,
+                       "originShield": null,
+                       "profileId": null,
+                       "protocol": 0,
+                       "qstringIgnore": 0,
+                       "rangeRequestHandling": 0,
+                       "regexRemap": null,
+                       "regionalGeoBlocking": false,
+                       "routingName": "test",
+                       "serviceCategory": null,
+                       "signed": false,
+                       "signingAlgorithm": null,
+                       "rangeSliceBlockSize": null,
+                       "sslKeyVersion": null,
+                       "tenant": "root",
+                       "tenantId": 1,
+                       "tlsVersions": [
+                               "1.2",
+                               "1.3"
+                       ],
+                       "topology": null,
+                       "trRequestHeaders": null,
+                       "trResponseHeaders": null,
+                       "type": "HTTP",
+                       "typeId": 1,
+                       "xmlId": "test"
+               }
+       ],
+       "origins": [
+               {
+                       "deliveryServiceId": 2,
+                       "fqdn": "example.com",
+                       "name": "test",
+                       "port": 80,
+                       "protocol": "http",
+                       "tenantId": 1
+               }
        ]
-}
+}
\ No newline at end of file
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 ecc4440235..cd94bcebd5 100644
--- a/traffic_ops/testing/api_contract/v4/data/response_template.json
+++ b/traffic_ops/testing/api_contract/v4/data/response_template.json
@@ -432,7 +432,10 @@
                 "type": "string"
             },
             "guid": {
-                "type": "null"
+                "type": [
+                    "null",
+                    "string"
+                ]
             },
             "hostName": {
                 "type": "string"
@@ -444,34 +447,61 @@
                 "type": "integer"
             },
             "iloIpAddress": {
-                "type": "null"
+                "type": [
+                    "null",
+                    "string"
+                ]
             },
             "iloIpGateway": {
-                "type": "null"
+                "type": [
+                    "null",
+                    "string"
+                ]
             },
             "iloIpNetmask": {
-                "type": "null"
+                "type": [
+                    "null",
+                    "string"
+                ]
             },
             "iloPassword": {
-                "type": "null"
+                "type": [
+                    "null",
+                    "string"
+                ]
             },
             "iloUsername": {
-                "type": "null"
+                "type": [
+                    "null",
+                    "string"
+                ]
             },
             "lastUpdated": {
                 "type": "string"
             },
             "mgmtIpAddress": {
-                "type": "null"
+                "type": [
+                    "null",
+                    "string"
+                ]
             },
             "mgmtIpGateway": {
-                "type": "null"
+                "type": [
+                    "null",
+                    "string"
+                ]
             },
             "mgmtIpNetmask": {
-                "type": "null"
+                "type": [
+                    "null",
+                    "string"
+                ]
             },
             "offlineReason": {
-                "type": "null"
+                "type": [
+                    "null",
+                    "string"
+                ]
             },
             "physLocation": {
                 "type": "string"
@@ -486,7 +516,10 @@
                 }
             },
             "rack": {
-                "type": "null"
+                "type": [
+                    "null",
+                    "string"
+                ]
             },
             "revalPending": {
                 "type": "boolean"
@@ -513,7 +546,10 @@
                 "type": "string"
             },
             "xmppPasswd": {
-                "type": "null"
+                "type": [
+                    "null",
+                    "string"
+                ]
             },
             "interfaces": {
                 "type": "array",
@@ -552,7 +588,10 @@
                             }
                         },
                         "maxBandwidth": {
-                            "type": "null"
+                            "type": [
+                                "null",
+                                "integer"
+                            ]
                         },
                         "monitor": {
                             "type": "boolean"
@@ -573,7 +612,10 @@
                 }
             },
             "statusLastUpdated": {
-                "type": "null"
+                "type": [
+                    "null",
+                    "string"
+                ]
             },
             "configUpdateTime": {
                 "type": "string"
@@ -611,5 +653,447 @@
                 "type": "string"
             }
         }
+    },
+    "delivery_services": {
+        "type": "object",
+        "properties": {
+            "maxRequestHeaderBytes": {
+                "type": "integer"
+            },
+            "firstHeaderRewrite": {
+                "type": [
+                    "null",
+                    "string"
+                ]
+            },
+            "innerHeaderRewrite": {
+                "type": [
+                    "null",
+                    "string"
+                ]
+            },
+            "lastHeaderRewrite": {
+                "type": [
+                    "null",
+                    "string"
+                ]
+            },
+            "serviceCategory": {
+                "type": [
+                    "null",
+                    "string"
+                ]
+            },
+            "topology": {
+                "type": [
+                    "null",
+                    "string"
+                ]
+            },
+            "ecsEnabled": {
+                "type": "boolean"
+            },
+            "rangeSliceBlockSize": {
+                "type": [
+                    "null",
+                    "integer"
+                ]
+            },
+            "consistentHashRegex": {
+                "type": [
+                    "null",
+                    "string"
+                ]
+            },
+            "consistentHashQueryParams": {
+                "type": "array",
+                "items": {}
+            },
+            "maxOriginConnections": {
+                "type": "integer"
+            },
+            "deepCachingType": {
+                "type": "string"
+            },
+            "fqPacingRate": {
+                "type": [
+                    "null",
+                    "integer"
+                ]
+            },
+            "signingAlgorithm": {
+                "type": [
+                    "null",
+                    "boolean"
+                ]
+            },
+            "tenant": {
+                "type": "string"
+            },
+            "trResponseHeaders": {
+                "type": [
+                    "null",
+                    "string"
+                ]
+            },
+            "trRequestHeaders": {
+                "type": [
+                    "null",
+                    "string"
+                ]
+            },
+            "active": {
+                "type": "boolean"
+            },
+            "anonymousBlockingEnabled": {
+                "type": "boolean"
+            },
+            "ccrDnsTtl": {
+                "type": [
+                    "null",
+                    "integer"
+                ]
+            },
+            "cdnId": {
+                "type": "integer"
+            },
+            "cdnName": {
+                "type": "string"
+            },
+            "checkPath": {
+                "type": [
+                    "null",
+                    "string"
+                ]
+            },
+            "displayName": {
+                "type": "string"
+            },
+            "dnsBypassCname": {
+                "type": [
+                    "null",
+                    "string"
+                ]
+            },
+            "dnsBypassIp": {
+                "type": [
+                    "null",
+                    "string"
+                ]
+            },
+            "dnsBypassIp6": {
+                "type": [
+                    "null",
+                    "string"
+                ]
+            },
+            "dnsBypassTtl": {
+                "type": [
+                    "null",
+                    "integer"
+                ]
+            },
+            "dscp": {
+                "type": "integer"
+            },
+            "edgeHeaderRewrite": {
+                "type": [
+                    "null",
+                    "string"
+                ]
+            },
+            "exampleURLs": {
+                "type": "array",
+                "items": {
+                    "type": "string"
+                }
+            },
+            "geoLimit": {
+                "type": "integer"
+            },
+            "geoLimitRedirectURL": {
+                "type": [
+                    "null",
+                    "string"
+                ]
+            },
+            "geoProvider": {
+                "type": "integer"
+            },
+            "globalMaxMbps": {
+                "type": [
+                    "null",
+                    "integer"
+                ]
+            },
+            "globalMaxTps": {
+                "type": [
+                    "null",
+                    "integer"
+                ]
+            },
+            "httpBypassFqdn": {
+                "type": [
+                    "null",
+                    "string"
+                ]
+            },
+            "id": {
+                "type": "integer"
+            },
+            "infoUrl": {
+                "type": [
+                    "null",
+                    "string"
+                ]
+            },
+            "initialDispersion": {
+                "type": "integer"
+            },
+            "ipv6RoutingEnabled": {
+                "type": "boolean"
+            },
+            "lastUpdated": {
+                "type": "string"
+            },
+            "logsEnabled": {
+                "type": "boolean"
+            },
+            "longDesc": {
+                "type": "string"
+            },
+            "matchList": {
+                "type": "array",
+                "items": {
+                    "type": "object",
+                    "properties": {
+                        "type": {
+                            "type": "string"
+                        },
+                        "setNumber": {
+                            "type": "integer"
+                        },
+                        "pattern": {
+                            "type": "string"
+                        }
+                    }
+                }
+            },
+            "maxDnsAnswers": {
+                "type": [
+                    "null",
+                    "integer"
+                ]
+            },
+            "midHeaderRewrite": {
+                "type": [
+                    "null",
+                    "string"
+                ]
+            },
+            "missLat": {
+                "type": "integer"
+            },
+            "missLong": {
+                "type": "integer"
+            },
+            "multiSiteOrigin": {
+                "type": "boolean"
+            },
+            "originShield": {
+                "type": [
+                    "null",
+                    "string"
+                ]
+            },
+            "orgServerFqdn": {
+                "type": "string"
+            },
+            "profileDescription": {
+                "type": [
+                    "null",
+                    "string"
+                ]
+            },
+            "profileId": {
+                "type": [
+                    "null",
+                    "integer"
+                ]
+            },
+            "profileName": {
+                "type": [
+                    "null",
+                    "string"
+                ]
+            },
+            "protocol": {
+                "type": "integer"
+            },
+            "qstringIgnore": {
+                "type": "integer"
+            },
+            "rangeRequestHandling": {
+                "type": "integer"
+            },
+            "regexRemap": {
+                "type": [
+                    "null",
+                    "string"
+                ]
+            },
+            "regionalGeoBlocking": {
+                "type": "boolean"
+            },
+            "remapText": {
+                "type": [
+                    "null",
+                    "string"
+                ]
+            },
+            "routingName": {
+                "type": "string"
+            },
+            "signed": {
+                "type": "boolean"
+            },
+            "sslKeyVersion": {
+                "type": [
+                    "null",
+                    "integer"
+                ]
+            },
+            "tenantId": {
+                "type": "integer"
+            },
+            "type": {
+                "type": "string"
+            },
+            "typeId": {
+                "type": "integer"
+            },
+            "xmlId": {
+                "type": "string"
+            },
+            "tlsVersions": {
+                "type": "array",
+                "items": {
+                    "type": "string"
+                }
+            },
+            "geoLimitCountries": {
+                "type": [
+                    "null",
+                    "array"
+                ]
+            }
+        }
+    },
+    "origins": {
+        "type": "object",
+        "required": [
+            "cachegroup",
+            "cachegroupId",
+            "coordinate",
+            "coordinateId",
+            "deliveryService",
+            "deliveryServiceId",
+            "fqdn",
+            "id",
+            "ip6Address",
+            "ipAddress",
+            "isPrimary",
+            "lastUpdated",
+            "name",
+            "port",
+            "profile",
+            "profileId",
+            "protocol",
+            "tenant",
+            "tenantId"
+        ],
+        "properties": {
+            "cachegroup": {
+                "type": [
+                    "string",
+                    "null"
+                ]
+            },
+            "cachegroupId": {
+                "type": [
+                    "integer",
+                    "null"
+                ]
+            },
+            "coordinate": {
+                "type": [
+                    "null",
+                    "string"
+                ]
+            },
+            "coordinateId": {
+                "type": [
+                    "integer",
+                    "null"
+                ]
+            },
+            "deliveryService": {
+                "type": "string"
+            },
+            "deliveryServiceId": {
+                "type": "integer"
+            },
+            "fqdn": {
+                "type": "string"
+            },
+            "id": {
+                "type": "integer"
+            },
+            "ip6Address": {
+                "type": [
+                    "null",
+                    "string"
+                ]
+            },
+            "ipAddress": {
+                "type": [
+                    "null",
+                    "string"
+                ]
+            },
+            "isPrimary": {
+                "type": "boolean"
+            },
+            "lastUpdated": {
+                "type": "string"
+            },
+            "name": {
+                "type": "string"
+            },
+            "port": {
+                "type": "integer"
+            },
+            "profile": {
+                "type": [
+                    "string",
+                    "null"
+                ]
+            },
+            "profileId": {
+                "type": [
+                    "integer",
+                    "null"
+                ]
+            },
+            "protocol": {
+                "type": "string"
+            },
+            "tenant": {
+                "type": "string"
+            },
+            "tenantId": {
+                "type": "integer"
+            }
+        }
     }
-}
+}
\ No newline at end of file
diff --git a/traffic_ops/testing/api_contract/v4/test_cachegroups.py 
b/traffic_ops/testing/api_contract/v4/test_cachegroups.py
index b65a445ae5..d4cf6ceadb 100644
--- a/traffic_ops/testing/api_contract/v4/test_cachegroups.py
+++ b/traffic_ops/testing/api_contract/v4/test_cachegroups.py
@@ -60,7 +60,7 @@ def test_cache_group_contract(to_session: TOSession,
 
                first_cache_group = cache_group_data[0]
                if not isinstance(first_cache_group, dict):
-                       raise TypeError("malformed API response; first Cache 
group in response is not an object")
+                       raise TypeError("malformed API response; first Cache 
group in response is not an dict")
                logger.info("Cachegroup API get response %s", first_cache_group)
                cache_group_response_template = 
response_template_data.get("cachegroup")
 
@@ -77,9 +77,7 @@ def test_cache_group_contract(to_session: TOSession,
                pytest.fail("API contract test failed for cachegroup endpoint: 
API response was malformed")
        finally:
                # Delete Cache group after test execution to avoid redundancy.
-               try:
-                       cache_group_id = cache_group_post_data["id"]
-                       
to_session.delete_cachegroups(cache_group_id=cache_group_id)
-               except IndexError:
+               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 9901fab773..79691777ec 100644
--- a/traffic_ops/testing/api_contract/v4/test_cdns.py
+++ b/traffic_ops/testing/api_contract/v4/test_cdns.py
@@ -76,9 +76,7 @@ def test_cdn_contract(
                pytest.fail("API contract test failed for cdn endpoint: API 
response was malformed")
        finally:
                # Delete CDN after test execution to avoid redundancy.
-               try:
-                       cdn_id = cdn_post_data["id"]
-                       to_session.delete_cdn_by_id(cdn_id=cdn_id)
-               except IndexError:
+               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_delivery_services.py 
b/traffic_ops/testing/api_contract/v4/test_delivery_services.py
new file mode 100644
index 0000000000..41e3963b5b
--- /dev/null
+++ b/traffic_ops/testing/api_contract/v4/test_delivery_services.py
@@ -0,0 +1,92 @@
+#
+# 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 delivery services 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_delivery_services_contract(to_session: TOSession,
+       response_template_data: dict[str, Union[Primitive, list[Union[Primitive,
+                                                       dict[str, object], 
list[object]]], dict[object, object]]],
+       delivery_services_post_data: dict[str, object]
+) -> None:
+       """
+       Test step to validate keys, values and data types from 
delivery_services 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 delivery_services_post_data: Fixture to get sample delivery 
service data and response.
+       """
+       # validate delivery services keys from api get response
+       logger.info("Accessing /delivery_services endpoint through Traffic ops 
session.")
+
+       delivery_services_id = delivery_services_post_data["id"]
+       if not isinstance(delivery_services_id, int):
+               raise TypeError("malformed API response; 'id' property not a 
integer")
+
+       delivery_services_get_response: tuple[
+               Union[dict[str, object], list[Union[dict[str, object], 
list[object], Primitive]], Primitive],
+               requests.Response
+       ] = to_session.get_deliveryservices(query_params={"id": 
delivery_services_id})
+       try:
+               delivery_services_data = delivery_services_get_response[0]
+               if not isinstance(delivery_services_data, list):
+                       raise TypeError("malformed API response; 'response' 
property not an array")
+
+               first_delivery_services = delivery_services_data[0]
+               if not isinstance(first_delivery_services, dict):
+                       raise TypeError("malformed API response; first 
delivery_services in response is not an dict")
+               logger.info("delivery_services Api response %s", 
first_delivery_services)
+               delivery_services_response_template = 
response_template_data.get("delivery_services")
+               if not isinstance(delivery_services_response_template, dict):
+                       raise TypeError(f"delivery_services response template 
data must be a dict, not '"
+                                                       
f"{type(delivery_services_response_template)}'")
+
+               keys = ["cdnId", "profileId", "type", "typeId", "tenantId", 
"xmlId"]
+               prereq_values = [delivery_services_post_data[key] for key in 
keys]
+               get_values = [first_delivery_services[key] for key in keys]
+
+               assert validate(instance=first_delivery_services,
+                 schema=delivery_services_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 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 7a464e7cc5..548a093222 100644
--- a/traffic_ops/testing/api_contract/v4/test_divisions.py
+++ b/traffic_ops/testing/api_contract/v4/test_divisions.py
@@ -56,7 +56,7 @@ def test_division_contract(to_session: TOSession,
 
                first_division = division_data[0]
                if not isinstance(first_division, dict):
-                       raise TypeError("malformed API response; first division 
in response is not an object")
+                       raise TypeError("malformed API response; first division 
in response is not an dict")
 
                logger.info("Division Api get response %s", first_division)
                division_response_template = 
response_template_data.get("divisions")
@@ -75,9 +75,7 @@ def test_division_contract(to_session: TOSession,
                pytest.fail("Failed due to malformation")
        finally:
                # Delete division after test execution to avoid redundancy.
-               try:
-                       division_id = division_post_data["id"]
-                       to_session.delete_division(division_id=division_id)
-               except IndexError:
+               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_origins.py 
b/traffic_ops/testing/api_contract/v4/test_origins.py
new file mode 100644
index 0000000000..0943b24b79
--- /dev/null
+++ b/traffic_ops/testing/api_contract/v4/test_origins.py
@@ -0,0 +1,88 @@
+#
+# 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 origins 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_origin_contract(
+       to_session: TOSession,
+       response_template_data: dict[str, Union[Primitive, list[Union[Primitive,
+                                                       dict[str, object], 
list[object]]], dict[object, object]]],
+       origin_post_data: dict[str, object]
+) -> None:
+       """
+       Test step to validate keys, values and data types from origins 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 origin_post_data: Fixture to get sample server data and actual 
origin response.
+       """
+       # validate origin keys from origin get response
+       logger.info("Accessing /origins endpoint through Traffic ops session.")
+
+       origin_id = origin_post_data.get("id")
+       if not isinstance(origin_id, int):
+               raise TypeError("malformed API response; 'id' property not a 
integer")
+
+       origin_get_response: tuple[
+               Union[dict[str, object], list[dict[str, object] | list[object] 
| Primitive], Primitive],
+               requests.Response
+       ] = to_session.get_origins(query_params={"id": origin_id})
+       try:
+               origin_data = origin_get_response[0]
+               if not isinstance(origin_data, list):
+                       raise TypeError("malformed API response; 'response' 
property not an array")
+
+               first_origin = origin_data[0]
+               if not isinstance(first_origin, dict):
+                       raise TypeError("malformed API response; first origin 
in response is not an dict")
+               logger.info("origin Api get response %s", first_origin)
+               origin_response_template = response_template_data.get("origins")
+               if not isinstance(origin_response_template, dict):
+                       raise TypeError(
+                               f"origin response template data must be a dict, 
not '{type(origin_response_template)}'")
+
+               keys = ["deliveryServiceId", "fqdn", "name", "port", 
"protocol", "tenantId"]
+               prereq_values = [origin_post_data[key] for key in keys]
+               get_values = [first_origin[key] for key in keys]
+
+               assert validate(instance=first_origin, 
schema=origin_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 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 62935d5e20..2cff807ed8 100644
--- a/traffic_ops/testing/api_contract/v4/test_parameters.py
+++ b/traffic_ops/testing/api_contract/v4/test_parameters.py
@@ -57,7 +57,7 @@ def test_parameter_contract(to_session: TOSession,
 
                first_parameter = parameter_data[0]
                if not isinstance(first_parameter, dict):
-                       raise TypeError("malformed API response; first 
Parameter in response is not an object")
+                       raise TypeError("malformed API response; first 
Parameter in response is not an dict")
                logger.info("Parameter Api get response %s", first_parameter)
 
                parameter_response_template = 
response_template_data.get("parameters")
@@ -78,9 +78,7 @@ def test_parameter_contract(to_session: TOSession,
                pytest.fail("API contract test failed for cdn endpoint: API 
response was malformed")
        finally:
                # Delete Parameter after test execution to avoid redundancy.
-               try:
-                       parameter_id = parameter_post_data["id"]
-                       to_session.delete_parameter(parameter_id=parameter_id)
-               except IndexError:
+               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 f6894864dc..ab32a602c9 100644
--- a/traffic_ops/testing/api_contract/v4/test_phys_locations.py
+++ b/traffic_ops/testing/api_contract/v4/test_phys_locations.py
@@ -57,7 +57,7 @@ def test_phys_locations_contract(to_session: TOSession,
 
                first_phys_location = phys_location_data[0]
                if not isinstance(first_phys_location, dict):
-                       raise TypeError("malformed API response; first 
phys_location in response is not an object")
+                       raise TypeError("malformed API response; first 
phys_location in response is not an dict")
 
                logger.info("phys_location Api response %s", 
first_phys_location)
                phys_location_response_template = 
response_template_data.get("phys_locations")
@@ -79,9 +79,12 @@ def test_phys_locations_contract(to_session: TOSession,
                pytest.fail("API contract test failed for phys_locations 
endpoint: API response was malformed")
        finally:
                # Delete phys_location after test execution to avoid redundancy.
-               try:
-                       physical_location_id = phys_locations_post_data["id"]
-                       
to_session.delete_physical_location(physical_location_id=physical_location_id)
-               except IndexError:
+               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 67e124645a..6745bcf8d0 100644
--- a/traffic_ops/testing/api_contract/v4/test_profiles.py
+++ b/traffic_ops/testing/api_contract/v4/test_profiles.py
@@ -56,7 +56,7 @@ def test_profile_contract(to_session: TOSession,
 
                first_profile = profile_data[0]
                if not isinstance(first_profile, dict):
-                       raise TypeError("malformed API response; first Profile 
in response is not an object")
+                       raise TypeError("malformed API response; first Profile 
in response is not an dict")
                logger.info("Profile Api get response %s", first_profile)
 
                profile_response_template = 
response_template_data.get("profiles")
@@ -75,9 +75,12 @@ def test_profile_contract(to_session: TOSession,
                pytest.fail("API contract test failed for cdn endpoint: API 
response was malformed")
        finally:
                # Delete Profile after test execution to avoid redundancy.
-               try:
-                       profile_id = profile_post_data["id"]
-                       to_session.delete_profile_by_id(profile_id=profile_id)
-               except IndexError:
+               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 7a0a6fb795..49fd985bd9 100644
--- a/traffic_ops/testing/api_contract/v4/test_regions.py
+++ b/traffic_ops/testing/api_contract/v4/test_regions.py
@@ -29,7 +29,7 @@ Primitive = Union[bool, int, float, str, None]
 
 
 def test_region_contract(to_session: TOSession,
-       response_template_data: dict[str, Union[Primitive, 
list[Union[Primitive, 
+       response_template_data: dict[str, Union[Primitive, list[Union[Primitive,
        dict[str, object], list[object]]], dict[object, object]]],
        region_post_data: dict[str, object]
        ) -> None:
@@ -57,7 +57,7 @@ def test_region_contract(to_session: TOSession,
 
                first_region = region_data[0]
                if not isinstance(first_region, dict):
-                       raise TypeError("malformed API response; first region 
in response is not an object")
+                       raise TypeError("malformed API response; first region 
in response is not an dict")
 
                logger.info("Region Api response %s", first_region)
                region_response_template = response_template_data.get("regions")
@@ -78,9 +78,12 @@ def test_region_contract(to_session: TOSession,
                pytest.fail("API contract test failed for regions endpoint: API 
response was malformed")
        finally:
                # Delete region after test execution to avoid redundancy.
-               try:
-                       region_name = region_post_data["name"]
-                       to_session.delete_region(query_params={"name": 
region_name})
-               except IndexError:
+               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 79b4bda342..16ba345e16 100644
--- a/traffic_ops/testing/api_contract/v4/test_roles.py
+++ b/traffic_ops/testing/api_contract/v4/test_roles.py
@@ -57,7 +57,7 @@ def test_role_contract(to_session: TOSession,
 
                first_role = role_data[0]
                if not isinstance(first_role, dict):
-                       raise TypeError("malformed API response; first role in 
response is not an object")
+                       raise TypeError("malformed API response; first role in 
response is not an dict")
                logger.info("Role Api get response %s", first_role)
 
                role_response_template = response_template_data.get("roles")
@@ -77,9 +77,7 @@ def test_role_contract(to_session: TOSession,
                pytest.fail("API contract test failed for roles endpoint: API 
response was malformed")
        finally:
                # Delete Role after test execution to avoid redundancy.
-               try:
-                       role_name = role_post_data["name"]
-                       to_session.delete_role(query_params={"name": role_name})
-               except IndexError:
+               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 59066d7302..adaa064c09 100644
--- a/traffic_ops/testing/api_contract/v4/test_server_capabilities.py
+++ b/traffic_ops/testing/api_contract/v4/test_server_capabilities.py
@@ -58,7 +58,7 @@ def test_server_capabilities_contract(to_session: TOSession,
 
                first_server_capabilities = server_capabilities_data[0]
                if not isinstance(first_server_capabilities, dict):
-                       raise TypeError("malformed API response; first 
server_capabilities in response is not an object")
+                       raise TypeError("malformed API response; first 
server_capabilities in response is not an dict")
                logger.info("Server capabilities Api get response %s", 
first_server_capabilities)
 
                response_template = 
response_template_data.get("server_capabilities")
@@ -75,9 +75,7 @@ def test_server_capabilities_contract(to_session: TOSession,
                pytest.fail("API contract test failed for server_capabilities: 
API response was malformed")
        finally:
                # Delete server_capabilities after test execution to avoid 
redundancy.
-               try:
-                       server_capability_name = 
server_capabilities_post_data["name"]
-                       
to_session.delete_server_capabilities(query_params={"name": 
server_capability_name})
-               except IndexError:
+               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 37d7245cfd..51c0eed475 100644
--- a/traffic_ops/testing/api_contract/v4/test_servers.py
+++ b/traffic_ops/testing/api_contract/v4/test_servers.py
@@ -41,6 +41,8 @@ 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):
@@ -57,7 +59,7 @@ def test_server_contract(to_session: TOSession,
 
                first_server = server_data[0]
                if not isinstance(first_server, dict):
-                       raise TypeError("malformed API response; first Server 
in response is not an object")
+                       raise TypeError("malformed API response; first Server 
in response is not an dict")
                logger.info("Server Api get response %s", first_server)
                server_response_template = response_template_data.get("servers")
                if not isinstance(server_response_template, dict):
@@ -76,9 +78,26 @@ def test_server_contract(to_session: TOSession,
                pytest.fail("API contract test failed for server endpoint: API 
response was malformed")
        finally:
                # Delete Server after test execution to avoid redundancy.
-               try:
-                       server_id = server_post_data["id"]
-                       to_session.delete_server_by_id(server_id=server_id)
-               except IndexError:
+               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_tenants.py 
b/traffic_ops/testing/api_contract/v4/test_tenants.py
index ee643b693b..eaaae253ee 100644
--- a/traffic_ops/testing/api_contract/v4/test_tenants.py
+++ b/traffic_ops/testing/api_contract/v4/test_tenants.py
@@ -57,7 +57,7 @@ def test_tenant_contract(to_session: TOSession,
 
                first_tenant = tenant_data[0]
                if not isinstance(first_tenant, dict):
-                       raise TypeError("malformed API response; first tenant 
in response is not an object")
+                       raise TypeError("malformed API response; first tenant 
in response is not an dict")
                logger.info("Tenant Api get response %s", first_tenant)
 
                tenant_response_template = response_template_data.get("tenants")
@@ -78,9 +78,7 @@ def test_tenant_contract(to_session: TOSession,
                pytest.fail("API contract test failed for tenants endpoint: API 
response was malformed")
        finally:
                # Delete tenant after test execution to avoid redundancy.
-               try:
-                       tenant_id = tenant_post_data["id"]
-                       to_session.delete_tenant(tenant_id=tenant_id)
-               except IndexError:
+               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")

Reply via email to