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

Reply via email to