You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficcontrol.apache.org by sh...@apache.org on 2023/03/28 16:23:40 UTC
[trafficcontrol] branch master updated: Various improvements to the API contract tests (#7419)
This is an automated email from the ASF dual-hosted git repository.
shamrick 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 67cf92d665 Various improvements to the API contract tests (#7419)
67cf92d665 is described below
commit 67cf92d665da915b0727145cb718d6fddd3ae1d1
Author: ocket8888 <oc...@apache.org>
AuthorDate: Tue Mar 28 10:23:32 2023 -0600
Various improvements to the API contract tests (#7419)
* Get rid of removed Pylint config option
* Use real indentation
* foo
* Slight formatting changes
* Greatly improve type safety in conftest main script
* fix use of reserved short option
* Fix URLs not allowed to omit port number
* Fix using deprecated log method
* add context to URL parsing errors
* Make prerequisite data file location configurable
* don't return duplicate data in the prerequisite fixture
* Make "cdns" an array
It's plural, so I assume that was the original intent
* Fix typechecking issues
* Fix linter errors
all but one were about lines being too long
---
traffic_control/clients/python/pylint.rc | 7 -
traffic_ops/testing/api_contract/v4/conftest.py | 393 +++++++++++++++------
.../testing/api_contract/v4/prerequisite_data.json | 14 +-
traffic_ops/testing/api_contract/v4/test_cdns.py | 152 +++++---
4 files changed, 399 insertions(+), 167 deletions(-)
diff --git a/traffic_control/clients/python/pylint.rc b/traffic_control/clients/python/pylint.rc
index 77d93556e1..aadd4fe56e 100644
--- a/traffic_control/clients/python/pylint.rc
+++ b/traffic_control/clients/python/pylint.rc
@@ -360,13 +360,6 @@ max-line-length=100
# Maximum number of lines in a module.
max-module-lines=1000
-# List of optional constructs for which whitespace checking is disabled. `dict-
-# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
-# `trailing-comma` allows a space between comma and closing bracket: (a, ).
-# `empty-line` allows space-only lines.
-no-space-check=trailing-comma,
- dict-separator
-
# Allow the body of a class to be on the same line as the declaration if body
# contains single statement.
single-line-class-stmt=no
diff --git a/traffic_ops/testing/api_contract/v4/conftest.py b/traffic_ops/testing/api_contract/v4/conftest.py
index 684089b6b0..bc2bb16f6f 100644
--- a/traffic_ops/testing/api_contract/v4/conftest.py
+++ b/traffic_ops/testing/api_contract/v4/conftest.py
@@ -12,132 +12,327 @@
# limitations under the License.
#
-"""This module is used to create a Traffic Ops session
-and to store prerequisite data for endpoints."""
+"""
+This module is used to create a Traffic Ops session and to store prerequisite
+data for endpoints.
+"""
+
import json
import logging
import sys
import os
from random import randint
-from typing import NamedTuple, Optional
+from typing import NamedTuple, Union, Optional, TypeAlias
from urllib.parse import urlparse
+
import pytest
import requests
+
from trafficops.tosession import TOSession
from trafficops.restapi import OperationError
-
# Create and configure logger
logger = logging.getLogger()
+JSONData: TypeAlias = Union[dict[str, object], list[object], bool, int, float, str | None]
+JSONData.__doc__ = """An alias for the kinds of data that JSON can encode."""
+
+class APIVersion(NamedTuple):
+ """Represents an API version."""
+ major: int
+ minor: int
+
+ @staticmethod
+ def from_string(ver_str: str) -> "APIVersion":
+ """
+ Instantiates a new version from a string.
+
+ >>> APIVersion.from_string("4.0")
+ APIVersion(major=4, minor=0)
+ >>> try:
+ ... APIVersion("not a version string")
+ ... except ValueError:
+ ... print("whoops")
+ ...
+ whoops
+ >>>
+ >>> try:
+ ... APIVersion("4.Q")
+ ... except ValueError:
+ ... print("whoops")
+ ...
+ whoops
+ """
+ parts = ver_str.split(".", 1)
+ if len(parts) != 2:
+ raise ValueError("invalid version; must be of the form '{{major}}.{{minor}}'")
+ return APIVersion(int(parts[0]), int(parts[1]))
+
+ def __str__(self) -> str:
+ """
+ Coalesces the version to a string.
+
+ >>> print(APIVersion(4, 1))
+ 4.1
+ """
+ return f"{self.major}.{self.minor}"
+
+APIVersion.major.__doc__ = """The API's major version number."""
+APIVersion.major.__doc__ = """The API's minor version number."""
class ArgsType(NamedTuple):
- """Represents the arguments needed to create Traffic Ops session.
-
- Attributes:
- user (str): The username used for authentication.
- password (str): The password used for authentication.
- url (str): The URL of the environment.
- port (int): The port number to use for session.
- api_version (float): The version number of the API to use.
- """
- user: str
- password: str
- url: str
- port: int
- api_version: float
+ """Represents the configuration needed to create Traffic Ops session."""
+ user: str
+ password: str
+ url: str
+ port: int
+ api_version: APIVersion
+ def __str__(self) -> str:
+ """
+ Formats the configuration as a string. Omits password and extraneous
+ properties.
+
+ >>> print(ArgsType("user", "password", "url", 420, APIVersion(4, 0)))
+ User: 'user', URL: 'url'
+ """
+ return f"User: '{self.user}', URL: '{self.url}'"
+
+
+ArgsType.user.__doc__ = """The username used for authentication."""
+ArgsType.password.__doc__ = """The password used for authentication."""
+ArgsType.url.__doc__ = """The URL of the environment."""
+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."""
def pytest_addoption(parser: pytest.Parser) -> None:
- """Passing in Traffic Ops arguments [Username, Password, Url and Hostname] from command line.
- :param parser: Parser to parse command line arguments
- """
- parser.addoption(
- "--to-user", action="store", help="User name for Traffic Ops Session."
- )
- parser.addoption(
- "--to-password", action="store", help="Password for Traffic Ops Session."
- )
- parser.addoption(
- "--to-url", action="store", help="Traffic Ops URL."
- )
+ """
+ Parses the Traffic Ops arguments from command line.
+ :param parser: Parser to parse command line arguments.
+ """
+ parser.addoption(
+ "--to-user", action="store", help="User name for Traffic Ops Session."
+ )
+ parser.addoption(
+ "--to-password", action="store", help="Password for Traffic Ops Session."
+ )
+ parser.addoption(
+ "--to-url", action="store", help="Traffic Ops URL."
+ )
+ parser.addoption(
+ "--config",
+ help="Path to configuration file.",
+ default=os.path.join(os.path.dirname(__file__), "to_data.json")
+ )
+ parser.addoption(
+ "--prerequisites",
+ help="Path to prerequisites file.",
+ default=os.path.join(os.path.dirname(__file__), "prerequisite_data.json")
+ )
+
+def coalesce_config(
+ arg: object | None,
+ file_key: str,
+ file_contents: dict[str, object | None] | None,
+ env_key: str
+) -> Optional[str]:
+ """
+ Coalesces configuration retrieved from different sources into a single
+ string.
+
+ This will raise a ValueError if the type of the configuration value in the
+ parsed configuration file is not a string.
+
+ In order of descending precedence this checks the command-line argument
+ value, the configuration file value, and then the environment variable
+ value.
+
+ :param arg: The command-line argument value.
+ :param file_key: The key under which to look in the parsed JSON configuration file data.
+ :param file_contents: The parsed JSON configuration file (if one was used).
+ :param env_key: The environment variable name to look for a value if one wasn't provided elsewhere.
+ :returns: The coalesced configuration value, or 'None' if no value could be determined.
+ """
+ if isinstance(arg, str):
+ return arg
+
+ if file_contents:
+ file_value = file_contents.get(file_key)
+ if isinstance(file_value, str):
+ return file_value
+ if file_value is not None:
+ raise ValueError(f"incorrect value; want: 'str', got: '{type(file_value)}'")
+
+ return os.environ.get(env_key)
+def parse_to_url(raw: str) -> tuple[APIVersion, int]:
+ """
+ Parses the API version and port number from a raw URL string.
+
+ >>> parse_to_url("https://trafficops.example.test:420/api/5.270)
+ (APIVersion(major=5, minor=270), 420)
+ >>> parse_to_url("trafficops.example.test")
+ (APIVersion(major=4, minor=0), 443)
+ """
+ parsed = urlparse(raw)
+ if not parsed.netloc:
+ raise ValueError("missing network location (hostname & optional port)")
+
+ if parsed.scheme and parsed.scheme.lower() != "https":
+ raise ValueError("invalid scheme; must use HTTPS")
+
+ port = 443
+ if ":" in parsed.netloc:
+ port_str = parsed.netloc.split(":")[-1]
+ try:
+ port = int(port_str)
+ except ValueError as e:
+ raise ValueError(f"invalid port number: {port_str}") from e
+
+ api_version = APIVersion(4, 0)
+ if parsed.path and parsed.path != "/":
+ ver_str = parsed.path.lstrip("/api/").split("/", 1)[0]
+ if not ver_str:
+ raise ValueError(f"invalid API path: {parsed.path} (should be e.g. '/api/4.0')")
+ api_version = APIVersion.from_string(ver_str)
+ else:
+ logging.warning("using default API version: %s", api_version)
+
+ return (api_version, port)
@pytest.fixture(name="to_args")
def to_data(pytestconfig: pytest.Config) -> ArgsType:
- """PyTest fixture to store Traffic ops arguments passed from command line.
- :param pytestconfig: Session-scoped fixture that returns the session's pytest.Config object
- :returns args: Return Traffic Ops arguments
- """
- with open(os.path.join(os.path.dirname(__file__), "to_data.json"),
- encoding="utf-8", mode="r") as session_file:
- session_data = json.load(session_file)
- to_user = pytestconfig.getoption("--to-user")
- to_password = pytestconfig.getoption("--to-password")
- to_url = pytestconfig.getoption("--to-url")
- api_version = urlparse(
- session_data.get("url")).path.strip("/").split("/")[1]
-
- if not all([to_user, to_password, to_url]):
- logger.info(
- "Traffic Ops session data were not passed from Command line Args.")
- args = ArgsType(user=session_data.get("user"), password=session_data.get(
- "password"), url=session_data.get("url"), port=session_data.get("port"),
- api_version=api_version)
-
- else:
- args = ArgsType(user=to_user, password=to_password, url=to_url,
- port=session_data.get("port"), api_version=api_version)
- logger.info("Parsed Traffic ops session data from args %s", args)
- return args
+ """
+ PyTest fixture to store Traffic ops arguments passed from command line.
+ :param pytestconfig: Session-scoped fixture that returns the session's pytest.Config object.
+ :returns: Configuration for connecting to Traffic Ops.
+ """
+ session_data: JSONData = None
+ cfg_path = pytestconfig.getoption("--config")
+ if isinstance(cfg_path, str):
+ try:
+ with open(cfg_path, encoding="utf-8", mode="r") as session_file:
+ session_data = json.load(session_file)
+ except (FileNotFoundError, PermissionError) as read_err:
+ raise ValueError(f"could not read configuration file at '{cfg_path}'") from read_err
+
+ if session_data is not None and not isinstance(session_data, dict):
+ raise ValueError(
+ f"invalid configuration file; expected top-level object, got: {type(session_data)}"
+ )
+
+ to_user = coalesce_config(pytestconfig.getoption("--to-user"), "user", session_data, "TO_USER")
+ if not to_user:
+ raise ValueError(
+ "Traffic Ops password is not configured - use '--to-password', the config file, or an "
+ "environment variable to do so"
+ )
+
+ to_password = coalesce_config(
+ pytestconfig.getoption("--to-password"),
+ "password",
+ session_data,
+ "TO_PASSWORD"
+ )
+
+ if not to_password:
+ raise ValueError(
+ "Traffic Ops password is not configured - use '--to-password', the config file, or an "
+ "environment variable to do so"
+ )
+ to_url = coalesce_config(pytestconfig.getoption("--to-url"), "url", session_data, "TO_USER")
+ if not to_url:
+ raise ValueError(
+ "Traffic Ops URL is not configured - use '--to-url', the config file, or an "
+ "environment variable to do so"
+ )
+
+ try:
+ api_version, port = parse_to_url(to_url)
+ except ValueError as e:
+ raise ValueError("invalid Traffic Ops URL") from e
+
+ return ArgsType(
+ to_user,
+ to_password,
+ to_url,
+ port,
+ api_version
+ )
@pytest.fixture(name="to_session")
def to_login(to_args: ArgsType) -> TOSession:
- """PyTest Fixture to create a Traffic Ops session from Traffic Ops Arguments
- passed as command line arguments in to_args fixture in conftest.
- :param to_args: Fixture to get Traffic ops session arguments
- :returns to_session: Return Traffic ops session
- """
- # Create a Traffic Ops V4 session and login
- to_url = urlparse(to_args.url)
- to_host = to_url.hostname
- try:
- to_session = TOSession(host_ip=to_host, host_port=to_args.port,
- api_version=to_args.api_version, ssl=True, verify_cert=False)
- logger.info("Established Traffic Ops Session.")
- except OperationError as error:
- logger.debug("%s", error, exc_info=True, stack_info=True)
- logger.error(
- "Failure in Traffic Ops session creation. Reason: %s", error)
- sys.exit(-1)
-
- # Login To TO_API
- to_session.login(to_args.user, to_args.password)
- logger.info("Successfully logged into Traffic Ops.")
- return to_session
+ """
+ PyTest Fixture to create a Traffic Ops session from Traffic Ops Arguments
+ passed as command line arguments in to_args fixture in conftest.
+
+ :param to_args: Fixture to get Traffic ops session arguments.
+ :returns: An authenticated Traffic Ops session.
+ """
+ # Create a Traffic Ops V4 session and login
+ to_url = urlparse(to_args.url)
+ to_host = to_url.hostname
+ try:
+ to_session = TOSession(
+ host_ip=to_host,
+ host_port=to_args.port,
+ api_version=str(to_args.api_version),
+ ssl=True,
+ verify_cert=False
+ )
+ logger.info("Established Traffic Ops Session.")
+ except OperationError as error:
+ logger.debug("%s", error, exc_info=True, stack_info=True)
+ logger.error("Failure in Traffic Ops session creation. Reason: %s", error)
+ sys.exit(-1)
+
+ # Login To TO_API
+ to_session.login(to_args.user, to_args.password)
+ logger.info("Successfully logged into Traffic Ops.")
+ return to_session
@pytest.fixture()
-def cdn_post_data(to_session: TOSession, cdn_prereq_data:
- object) -> Optional[list[dict[str, str] | requests.Response]]:
- """PyTest Fixture to create POST data for cdns endpoint.
- :param to_session: Fixture to get Traffic ops session
- :param get_cdn_data: Fixture to get cdn data from a prereq file
- :returns prerequisite_data: Returns sample Post data and actual api response
- """
-
- # Return new post data and post response from cdns POST request
- cdn_prereq_data["name"] = cdn_prereq_data["name"][:4]+str(randint(0, 1000))
- cdn_prereq_data["domainName"] = cdn_prereq_data["domainName"][:5] + \
- str(randint(0, 1000))
- logger.info("New cdn data to hit POST method %s", cdn_prereq_data)
- # Hitting cdns POST methed
- response = to_session.create_cdn(data=cdn_prereq_data)
- prerequisite_data = None
- try:
- cdn_response = response[0]
- prerequisite_data = [cdn_prereq_data, cdn_response]
- except IndexError:
- logger.error("No CDN response data from cdns POST request.")
- return prerequisite_data
+def cdn_post_data(to_session: TOSession, cdn_prereq_data: list[JSONData]) -> dict[str, object]:
+ """
+ PyTest Fixture to create POST data for cdns endpoint.
+
+ :param to_session: Fixture to get Traffic Ops session.
+ :param get_cdn_data: Fixture to get CDN data from a prerequisites file.
+ :returns: Sample POST data and the actual API response.
+ """
+
+ try:
+ cdn = cdn_prereq_data[0]
+ except IndexError as e:
+ raise TypeError("malformed prerequisite data; no CDNs present in 'cdns' array property") from e
+
+ if not isinstance(cdn, dict):
+ raise TypeError(f"malformed prerequisite data; CDNs must be objects, not '{type(cdn)}'")
+
+ # Return new post data and post response from cdns POST request
+ randstr = str(randint(0, 1000))
+ try:
+ name = cdn["name"]
+ if not isinstance(name, str):
+ raise TypeError(f"name must be str, not '{type(name)}'")
+ cdn["name"] = name[:4] + randstr
+ domain_name = cdn["domainName"]
+ if not isinstance(domain_name, str):
+ raise TypeError(f"domainName must be str, not '{type(domain_name)}")
+ cdn["domainName"] = domain_name[:5] + randstr
+ except KeyError as e:
+ raise TypeError(f"missing CDN property '{e.args[0]}'") from e
+
+ logger.info("New cdn data to hit POST method %s", cdn_prereq_data)
+ # Hitting cdns POST methed
+ response: tuple[JSONData, requests.Response] = to_session.create_cdn(data=cdn)
+ try:
+ resp_obj = response[0]
+ if not isinstance(resp_obj, dict):
+ raise TypeError("malformed API response; cdn is not an object")
+ return resp_obj
+ except IndexError:
+ logger.error("No CDN response data from cdns POST request.")
+ sys.exit(1)
diff --git a/traffic_ops/testing/api_contract/v4/prerequisite_data.json b/traffic_ops/testing/api_contract/v4/prerequisite_data.json
index 4939bbe284..2acf4b7801 100644
--- a/traffic_ops/testing/api_contract/v4/prerequisite_data.json
+++ b/traffic_ops/testing/api_contract/v4/prerequisite_data.json
@@ -1,9 +1,9 @@
{
- "cdns": {
- "name": "test",
- "domainName": "quest",
- "dnssecEnabled": false,
- "id": null,
- "lastUpdated": null
- }
+ "cdns": [{
+ "name": "test",
+ "domainName": "quest",
+ "dnssecEnabled": false,
+ "id": null,
+ "lastUpdated": null
+ }]
}
diff --git a/traffic_ops/testing/api_contract/v4/test_cdns.py b/traffic_ops/testing/api_contract/v4/test_cdns.py
index 9b7e4d2491..e146ab579e 100644
--- a/traffic_ops/testing/api_contract/v4/test_cdns.py
+++ b/traffic_ops/testing/api_contract/v4/test_cdns.py
@@ -12,68 +12,112 @@
# limitations under the License.
#
-"""Api Contract Test Case for cdns endpoint."""
+"""API Contract Test Case for cdns endpoint."""
import json
import logging
-import os
+
import pytest
import requests
+
from trafficops.tosession import TOSession
# Create and configure logger
logger = logging.getLogger()
+primitive = bool | int | float | str | None
@pytest.fixture(name="cdn_prereq_data")
-def get_cdn_prereq_data() -> object:
- """PyTest Fixture to store prereq data for cdns endpoint.
- :returns cdn_data: Returns prerequisite data for cdns endpoint
- """
- # Response keys for cdns endpoint
- with open(os.path.join(os.path.dirname(__file__), "prerequisite_data.json"),
- encoding="utf-8", mode="r") as prereq_file:
- data = json.load(prereq_file)
- cdn_data = data["cdns"]
- return cdn_data
-
-
-def test_cdn_contract(to_session: TOSession, cdn_prereq_data: object,
- cdn_post_data: list[dict[str, str] | requests.Response]) -> None:
- """Test step to validate keys, values and data types from cdns endpoint response.
- :param to_session: Fixture to get Traffic ops session
- :param get_cdn_data: Fixture to get cdn data from a prereq file
- :param cdn_prereq: Fixture to get sample cdn data and actual cdn response
- """
- # validate CDN keys from cdns get response
- logger.info("Accessing Cdn endpoint through Traffic ops session.")
- cdn_name = cdn_post_data[0]["name"]
- cdn_get_response = to_session.get_cdns(
- query_params={"name": cdn_name})
- try:
- cdn_data = cdn_get_response[0]
- cdn_keys = list(cdn_data[0].keys())
- logger.info(
- "CDN Keys from cdns endpoint response %s", cdn_keys)
- # validate cdn values from prereq data in cdns get response.
- prereq_values = [cdn_post_data[0]["name"], cdn_post_data[0]
- ["domainName"], cdn_post_data[0]["dnssecEnabled"]]
- get_values = [cdn_data[0]["name"], cdn_data[0]
- ["domainName"], cdn_data[0]["dnssecEnabled"]]
- # validate data types for values from cdn get json response.
- for (prereq_value, get_value) in zip(prereq_values, get_values):
- assert isinstance(prereq_value, type(get_value))
- assert cdn_keys.sort() == list(cdn_prereq_data.keys()).sort()
- assert get_values == prereq_values
- except IndexError:
- logger.error("No CDN data from cdns get request")
- pytest.fail("Response from get request is empty, Failing test_get_cdn")
- finally:
- # Delete CDN after test execution to avoid redundancy.
- try:
- cdn_response = cdn_post_data[1]
- cdn_id = cdn_response["id"]
- to_session.delete_cdn_by_id(cdn_id=cdn_id)
- except IndexError:
- logger.error("CDN wasn't created")
- pytest.fail(
- "Response from delete request is empty, Failing test_get_cdn")
+def get_cdn_prereq_data(
+ pytestconfig: pytest.Config
+) -> list[dict[str, object] | list[object] | primitive]:
+ """
+ PyTest Fixture to store POST request body data for cdns endpoint.
+
+ :returns: Prerequisite data for cdns endpoint.
+ """
+ prereq_path = pytestconfig.getoption("prerequisites")
+ if not isinstance(prereq_path, str):
+ # unlike the configuration file, this must be present
+ raise ValueError("prereqisites path not configured")
+
+ # Response keys for cdns endpoint
+ data: dict[
+ str,
+ list[dict[str, object] | list[object] | primitive] |\
+ dict[object, object] |\
+ primitive
+ ] |\
+ primitive = None
+ with open(prereq_path, encoding="utf-8", mode="r") as prereq_file:
+ data = json.load(prereq_file)
+ if not isinstance(data, dict):
+ raise TypeError(f"prerequisite data must be an object, not '{type(data)}'")
+
+ cdn_data = data["cdns"]
+ if not isinstance(cdn_data, list):
+ raise TypeError(f"cdns data must be a list, not '{type(cdn_data)}'")
+
+ return cdn_data
+
+
+def test_cdn_contract(
+ to_session: TOSession,
+ cdn_prereq_data: list[dict[str, object] | list[object] | primitive],
+ cdn_post_data: dict[str, object]
+) -> None:
+ """
+ Test step to validate keys, values and data types from cdns endpoint
+ response.
+ :param to_session: Fixture to get Traffic Ops session.
+ :param get_cdn_data: Fixture to get CDN data from a prerequisites file.
+ :param cdn_prereq: Fixture to get sample CDN data and actual CDN response.
+ """
+ # validate CDN keys from cdns get response
+ logger.info("Accessing /cdns endpoint through Traffic ops session.")
+
+ cdn = cdn_prereq_data[0]
+ if not isinstance(cdn, dict):
+ raise TypeError("malformed cdn in prerequisite data; not an object")
+
+ cdn_name = cdn.get("name")
+ if not isinstance(cdn_name, str):
+ raise TypeError("malformed cdn in prerequisite data; 'name' not a string")
+
+ cdn_get_response: tuple[
+ dict[str, object] | list[dict[str, object] | list[object] | primitive] | primitive,
+ requests.Response
+ ] = to_session.get_cdns(query_params={"name": cdn_name})
+ try:
+ cdn_data = cdn_get_response[0]
+ if not isinstance(cdn_data, list):
+ raise TypeError("malformed API response; 'response' property not an array")
+
+ first_cdn = cdn_data[0]
+ if not isinstance(first_cdn, dict):
+ raise TypeError("malformed API response; first CDN in response is not an object")
+ cdn_keys = set(first_cdn.keys())
+
+ logger.info("CDN Keys from cdns endpoint response %s", cdn_keys)
+ # validate cdn values from prereq data in cdns get response.
+ prereq_values = [
+ cdn_post_data["name"],
+ cdn_post_data["domainName"],
+ cdn_post_data["dnssecEnabled"]
+ ]
+ get_values = [first_cdn["name"], first_cdn["domainName"], first_cdn["dnssecEnabled"]]
+ # validate data types for values from cdn get json response.
+ for (prereq_value, get_value) in zip(prereq_values, get_values):
+ assert isinstance(prereq_value, type(get_value))
+ assert cdn_keys == set(cdn_post_data.keys())
+ assert get_values == prereq_values
+ except IndexError:
+ logger.error("Either prerequisite data or API response was malformed")
+ pytest.fail("Either prerequisite data or 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:
+ logger.error("CDN returned by Traffic Ops is missing an 'id' property")
+ pytest.fail("Response from delete request is empty, Failing test_get_cdn")