This is an automated email from the ASF dual-hosted git repository.
ocket8888 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 048711cf86 Adding API Contract Test for cdns endpoint (#7400)
048711cf86 is described below
commit 048711cf86dc9b3ec1edb128cfdbbc14d700bd69
Author: Gokula Krishnan S <[email protected]>
AuthorDate: Thu Mar 23 00:40:06 2023 +0530
Adding API Contract Test for cdns endpoint (#7400)
* Added cdns api contract TC and conftest to store fixtures
* Added checks for test_get_cdn and test_post_cdn
* Remove file endpoint_data.json
* Modified code
* Rename post_data.json to prerequisite_data.json
* Update conftest.py
* Update test_cdns.py
* Update conftest.py
* Added requirements file
* Added setup.py file
* Update setup.py
* Update setup.py
* Addressed review comments
* removed setup.py file
* modified code
* Updated code
* Added param description in doc string
* Added check for validating datatypes in Json Response and README file
* modififed conftest.py
* modifed README
* Addressed review comments
* Addressed Review comments
* Addressed Review comments
* Addressed Review comments
* Addressed review comments
* Addressed review comments
* Addressed review comments
---------
Co-authored-by: Gokula krishnan <[email protected]>
---
traffic_ops/testing/api_contract/README.md | 52 ++++++++
traffic_ops/testing/api_contract/v4/conftest.py | 143 +++++++++++++++++++++
.../testing/api_contract/v4/prerequisite_data.json | 9 ++
traffic_ops/testing/api_contract/v4/pytest.ini | 20 +++
.../testing/api_contract/v4/requirements.txt | 16 +++
traffic_ops/testing/api_contract/v4/test_cdns.py | 79 ++++++++++++
traffic_ops/testing/api_contract/v4/to_data.json | 6 +
7 files changed, 325 insertions(+)
diff --git a/traffic_ops/testing/api_contract/README.md
b/traffic_ops/testing/api_contract/README.md
new file mode 100644
index 0000000000..ce08da215c
--- /dev/null
+++ b/traffic_ops/testing/api_contract/README.md
@@ -0,0 +1,52 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you 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.
+-->
+
+# Traffic Ops API contract tests
+
+The Traffic Ops API contract tests are used to validate the Traffic Ops API's.
+
+## Setup
+
+In order to run the tests you will need a running instance of Traffic Ops and
Traffic Ops DB:
+
+1. Follow the instructions for building and running Traffic Ops from docs.
+
+2. Install the requirements for testing API contract tests.
+
+ ```console
+ pip install -r /path/to/requirements.txt
+ ```
+
+## Running the API contract tests
+
+The API contract tests are run using `pytest` from the
``traffic_ops/testing/api_contract/v4`` directory.
+
+Example commands to run the tests:
+
+Only test a specific endpoint with arguments.
+> Note: For particular environments (Step 1 is not mandatory)
+```console
+pytest --to-user Username --to-password Password --to-url URL test_cdns.py
+```
+
+Only test a specific endpoint with local Traffic Ops instance.
+> Note: For local environment (Step 1 is mandatory)
+```console
+pytest -rA test_cdns.py
+```
diff --git a/traffic_ops/testing/api_contract/v4/conftest.py
b/traffic_ops/testing/api_contract/v4/conftest.py
new file mode 100644
index 0000000000..684089b6b0
--- /dev/null
+++ b/traffic_ops/testing/api_contract/v4/conftest.py
@@ -0,0 +1,143 @@
+#
+# 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.
+#
+
+"""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 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()
+
+
+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
+
+
+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."
+ )
+
+
[email protected](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
+
+
[email protected](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
+
+
[email protected]()
+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
diff --git a/traffic_ops/testing/api_contract/v4/prerequisite_data.json
b/traffic_ops/testing/api_contract/v4/prerequisite_data.json
new file mode 100644
index 0000000000..4939bbe284
--- /dev/null
+++ b/traffic_ops/testing/api_contract/v4/prerequisite_data.json
@@ -0,0 +1,9 @@
+{
+ "cdns": {
+ "name": "test",
+ "domainName": "quest",
+ "dnssecEnabled": false,
+ "id": null,
+ "lastUpdated": null
+ }
+}
diff --git a/traffic_ops/testing/api_contract/v4/pytest.ini
b/traffic_ops/testing/api_contract/v4/pytest.ini
new file mode 100644
index 0000000000..4fac4d37ae
--- /dev/null
+++ b/traffic_ops/testing/api_contract/v4/pytest.ini
@@ -0,0 +1,20 @@
+#
+# 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.
+#
+
+[pytest]
+
+log_cli = 1
+log_cli_level = INFO
+log_cli_format = %(asctime)s [%(levelname)8s] %(message)s
(%(filename)s:%(lineno)s)
+log_cli_date_format=%Y-%m-%dT%H:%M:%S
diff --git a/traffic_ops/testing/api_contract/v4/requirements.txt
b/traffic_ops/testing/api_contract/v4/requirements.txt
new file mode 100644
index 0000000000..81b9257263
--- /dev/null
+++ b/traffic_ops/testing/api_contract/v4/requirements.txt
@@ -0,0 +1,16 @@
+#
+# 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.
+#
+
+Apache-TrafficControl==3.1.0
+pytest==7.2.1
diff --git a/traffic_ops/testing/api_contract/v4/test_cdns.py
b/traffic_ops/testing/api_contract/v4/test_cdns.py
new file mode 100644
index 0000000000..9b7e4d2491
--- /dev/null
+++ b/traffic_ops/testing/api_contract/v4/test_cdns.py
@@ -0,0 +1,79 @@
+#
+# 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 cdns endpoint."""
+import json
+import logging
+import os
+import pytest
+import requests
+from trafficops.tosession import TOSession
+
+# Create and configure logger
+logger = logging.getLogger()
+
+
[email protected](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")
diff --git a/traffic_ops/testing/api_contract/v4/to_data.json
b/traffic_ops/testing/api_contract/v4/to_data.json
new file mode 100644
index 0000000000..903a0434a8
--- /dev/null
+++ b/traffic_ops/testing/api_contract/v4/to_data.json
@@ -0,0 +1,6 @@
+{
+ "user": "admin",
+ "password": "twelve12",
+ "url": "https://localhost/api/4.0",
+ "port": 443
+}
\ No newline at end of file