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

rshah 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 7e6e663a7e Added Api contract test case for tenants endpoint (#7449)
7e6e663a7e is described below

commit 7e6e663a7e2eecdcb74ed2e63703c55f65d3be42
Author: Gokula Krishnan <[email protected]>
AuthorDate: Tue Apr 25 20:39:29 2023 +0530

    Added Api contract test case for tenants endpoint (#7449)
    
    * Added Api contract test case for tenants endpoint
    
    * Addressed comments
    
    ---------
    
    Co-authored-by: Gokula krishnan <[email protected]>
---
 .../clients/python/trafficops/tosession.py         |  11 +++
 traffic_ops/testing/api_contract/v4/conftest.py    |  44 +++++++++
 .../testing/api_contract/v4/request_template.json  |   7 ++
 .../testing/api_contract/v4/response_template.json |  23 +++++
 .../testing/api_contract/v4/test_tenants.py        | 108 +++++++++++++++++++++
 5 files changed, 193 insertions(+)

diff --git a/traffic_control/clients/python/trafficops/tosession.py 
b/traffic_control/clients/python/trafficops/tosession.py
index dc26294f75..de74cded56 100644
--- a/traffic_control/clients/python/trafficops/tosession.py
+++ b/traffic_control/clients/python/trafficops/tosession.py
@@ -1847,6 +1847,17 @@ class TOSession(RestApiSession):
                :rtype: Tuple[Union[Dict[str, Any], List[Dict[str, Any]]], 
requests.Response]
                :raises: Union[LoginError, OperationError]
                """
+       
+       @api_request('delete', 'tenants/{tenant_id:d}', ('3.0', '4.0', '4.1', 
'5.0'))
+       def delete_tenant(self, tenant_id=None):
+               """
+               Delete a tenant
+               :ref:`to-api-tenants-id`
+               :param tenant_id: The tenant to delete
+               :type tenant_id: int
+               :rtype: Tuple[Union[Dict[str, Any], List[Dict[str, Any]]], 
requests.Response]
+               :raises: Union[LoginError, OperationError]
+               """
 
 
        #
diff --git a/traffic_ops/testing/api_contract/v4/conftest.py 
b/traffic_ops/testing/api_contract/v4/conftest.py
index eb9a9c0d4c..2f9f6365bc 100644
--- a/traffic_ops/testing/api_contract/v4/conftest.py
+++ b/traffic_ops/testing/api_contract/v4/conftest.py
@@ -628,3 +628,47 @@ def profile_post_data(to_session: TOSession, 
request_template_data: list[JSONDat
        except IndexError:
                logger.error("No Profile response data from cdns POST request.")
                sys.exit(1)
+
+
[email protected]()
+def tenant_post_data(to_session: TOSession, request_template_data: 
list[JSONData]
+                 ) -> dict[str, object]:
+       """
+       PyTest Fixture to create POST data for tenants endpoint.
+
+       :param to_session: Fixture to get Traffic Ops session.
+       :param request_template_data: Fixture to get tenant request template 
from a prerequisites file.
+       :returns: Sample POST data and the actual API response.
+       """
+
+       try:
+               tenant = request_template_data[0]
+       except IndexError as e:
+               raise TypeError(
+                       "malformed prerequisite data; no Parameters present in 
'tenants' array property") from e
+
+       if not isinstance(tenant, dict):
+               raise TypeError(
+                       f"malformed prerequisite data; tenants must be objects, 
not '{type(tenant)}'")
+
+       # Return new post data and post response from tenants POST request
+       randstr = str(randint(0, 1000))
+       try:
+               name = tenant["name"]
+               if not isinstance(name, str):
+                       raise TypeError(f"name must be str, not '{type(name)}'")
+               tenant["name"] = name[:4] + randstr
+       except KeyError as e:
+               raise TypeError(f"missing tenant property '{e.args[0]}'") from e
+
+       logger.info("New tenant data to hit POST method %s", 
request_template_data)
+       # Hitting tenants POST methed
+       response: tuple[JSONData, requests.Response] = 
to_session.create_tenant(data=tenant)
+       try:
+               resp_obj = response[0]
+               if not isinstance(resp_obj, dict):
+                       raise TypeError("malformed API response; parameter is 
not an object")
+               return resp_obj
+       except IndexError:
+               logger.error("No Parameter response data from parameters POST 
request.")
+               sys.exit(1)
diff --git a/traffic_ops/testing/api_contract/v4/request_template.json 
b/traffic_ops/testing/api_contract/v4/request_template.json
index 6177d6cc06..a7e2638b96 100644
--- a/traffic_ops/testing/api_contract/v4/request_template.json
+++ b/traffic_ops/testing/api_contract/v4/request_template.json
@@ -43,5 +43,12 @@
                        "type": "UNK_PROFILE",
                        "routingDisabled": true
                }
+       ],
+       "tenants": [
+               {
+                       "active": true,
+                       "name": "test",
+                       "parentId": 1
+               }
        ]
 }
diff --git a/traffic_ops/testing/api_contract/v4/response_template.json 
b/traffic_ops/testing/api_contract/v4/response_template.json
index 5130b47045..46c4ecebf0 100644
--- a/traffic_ops/testing/api_contract/v4/response_template.json
+++ b/traffic_ops/testing/api_contract/v4/response_template.json
@@ -149,5 +149,28 @@
                 "type": "str"
             }
         }
+    },
+    "tenants": {
+        "type": "object",
+        "properties": {
+            "id": {
+                "type": "int"
+            },
+            "name": {
+                "type": "str"
+            },
+            "active": {
+                "type": "bool"
+            },
+            "parentId": {
+                "type": "int"
+            },
+            "lastUpdated": {
+                "type": "str"
+            },
+            "parentName": {
+                "type": "str"
+            }
+        }
     }
 }
diff --git a/traffic_ops/testing/api_contract/v4/test_tenants.py 
b/traffic_ops/testing/api_contract/v4/test_tenants.py
new file mode 100644
index 0000000000..9ff9cd0e57
--- /dev/null
+++ b/traffic_ops/testing/api_contract/v4/test_tenants.py
@@ -0,0 +1,108 @@
+#
+# 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 tenants endpoint."""
+import logging
+import pytest
+import requests
+
+from trafficops.tosession import TOSession
+
+# Create and configure logger
+logger = logging.getLogger()
+
+primitive = bool | int | float | str | None
+
[email protected]('request_template_data', ["tenants"], indirect=True)
+def test_tenant_contract(
+       to_session: TOSession,
+       request_template_data: list[dict[str, object] | list[object] | 
primitive],
+       response_template_data: dict[str, primitive | list[primitive | 
dict[str, object]
+                                                   | list[object]] | 
dict[object, object]],
+       tenant_post_data: dict[str, object]
+) -> None:
+       """
+       Test step to validate keys, values and data types from tenants endpoint
+       response.
+       :param to_session: Fixture to get Traffic Ops session.
+       :param request_template_data: Fixture to get request template data from 
a prerequisites file.
+       :param response_template_data: Fixture to get response template data 
from a prerequisites file.
+       :param tenant_post_data: Fixture to get sample tenant data and actual 
tenant response.
+       """
+       # validate tenant keys from tenants get response
+       logger.info("Accessing /tenants endpoint through Traffic ops session.")
+
+       tenant = request_template_data[0]
+       if not isinstance(tenant, dict):
+               raise TypeError("malformed tenant in prerequisite data; not an 
object")
+
+       tenant_name = tenant.get("name")
+       if not isinstance(tenant_name, str):
+               raise TypeError("malformed tenant in prerequisite data; 'name' 
not a string")
+
+       tenant_get_response: tuple[
+               dict[str, object] | list[dict[str, object] | list[object] | 
primitive] | primitive,
+               requests.Response
+       ] = to_session.get_tenants(query_params={"name": tenant_name})
+       try:
+               tenant_data = tenant_get_response[0]
+               if not isinstance(tenant_data, list):
+                       raise TypeError("malformed API response; 'response' 
property not an array")
+
+               first_tenant = tenant_data[0]
+               if not isinstance(first_tenant, dict):
+                       raise TypeError("malformed API response; first tenant 
in response is not an object")
+               tenant_keys = set(first_tenant.keys())
+
+               logger.info("tenant Keys from tenants endpoint response %s", 
tenant_keys)
+               tenant_response_template = response_template_data.get("tenants")
+               if not isinstance(tenant_response_template, dict):
+                       raise TypeError(
+                               f"tenant response template data must be a dict, 
not '{type(tenant_response_template)}'")
+               response_template: dict[str, list[dict[str, object] | 
list[object] | primitive] |\
+                       dict[object, object] |\
+                       primitive
+               ]
+               response_template = tenant_response_template.get("properties")
+               # validate tenant values from prereq data in tenants get 
response.
+               prereq_values = [tenant_post_data["name"], 
tenant_post_data["active"],
+               tenant_post_data["parentId"]]
+               get_values = [first_tenant["name"], first_tenant["active"], 
first_tenant["parentId"]]
+               get_types = {}
+               for key, value in first_tenant.items():
+                       get_types[key] = type(value).__name__
+               logger.info("types from tenant get response %s", get_types)
+               response_template_types= {}
+               for key, value in response_template.items():
+                       actual_type = value.get("type")
+                       if not isinstance(actual_type, str):
+                               raise TypeError(
+                                       f"Type data must be a string, not 
'{type(actual_type)}'")
+                       response_template_types[key] = actual_type
+               logger.info("types from tenants response template %s", 
response_template_types)
+               # validate keys, data types and values from tenants get json 
response.
+               assert tenant_keys == set(response_template.keys())
+               assert dict(sorted(get_types.items())) == 
dict(sorted(response_template_types.items()))
+               assert get_values == prereq_values
+       except IndexError:
+               logger.error("Either prerequisite data or API response was 
malformed")
+               pytest.fail("API contract test failed for tenants endpoint: API 
response was malformed")
+       finally:
+               # Delete tenant after test execution to avoid redundancy.
+               try:
+                       tenant_id = tenant_post_data["id"]
+                       to_session.delete_tenant(tenant_id=tenant_id)
+               except IndexError:
+                       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