Skip to content

Commit

Permalink
Added API Contract testcase for Coordinates endpoint (apache#7576)
Browse files Browse the repository at this point in the history
coordinates test passing

Co-authored-by: yblanc545 <[email protected]>
  • Loading branch information
Kashatlast2 and yblanc545 authored Jun 13, 2023
1 parent 6b3aa45 commit 3bc814a
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 0 deletions.
28 changes: 28 additions & 0 deletions traffic_ops/testing/api_contract/v4/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -990,3 +990,31 @@ def asn_data_post(to_session: TOSession, request_template_data: list[JSONData],
response: tuple[JSONData, requests.Response] = to_session.create_asn(data=asn)
resp_obj = check_template_data(response, "asn")
return resp_obj

@pytest.fixture(name="coordinate_post_data")
def coordinate_data_post(to_session: TOSession, request_template_data: list[JSONData]
) -> dict[str, object]:
"""
PyTest Fixture to create POST data for coordinates endpoint.
:param to_session: Fixture to get Traffic Ops session.
:param request_template_data: Fixture to get coordinate request template from a prerequisites file.
:returns: Sample POST data and the actual API response.
"""

coordinate = check_template_data(request_template_data["coordinates"], "coordinates")

# Return new post data and post response from coordinates POST request
randstr = str(randint(0, 1000))
try:
name = coordinate["name"]
if not isinstance(name, str):
raise TypeError(f"name must be str, not '{type(name)}'")
coordinate["name"] = name[:4] + randstr
except KeyError as e:
raise TypeError(f"missing coordinate property '{e.args[0]}'") from e

logger.info("New coordinate data to hit POST method %s", coordinate)
# Hitting coordinates POST methed
response: tuple[JSONData, requests.Response] = to_session.create_coordinates(data=coordinate)
resp_obj = check_template_data(response, "coordinate")
return resp_obj
Original file line number Diff line number Diff line change
Expand Up @@ -219,5 +219,12 @@
"asn": 1,
"cachegroupId": 10
}
],
"coordinates": [
{
"name": "test",
"latitude": 38.897663,
"longitude": -77.036574
}
]
}
27 changes: 27 additions & 0 deletions traffic_ops/testing/api_contract/v4/data/response_template.json
Original file line number Diff line number Diff line change
Expand Up @@ -1122,5 +1122,32 @@
"type": "string"
}
}
},
"coordinates": {
"type": "object",
"required": [
"id",
"name",
"latitude",
"longitude",
"lastUpdated"
],
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"latitude": {
"type": "number"
},
"longitude": {
"type": "number"
},
"lastUpdated": {
"type": "string"
}
}
}
}
84 changes: 84 additions & 0 deletions traffic_ops/testing/api_contract/v4/test_coordinates.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#
# 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 coordinates 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_coordinate_contract(to_session: TOSession,
response_template_data: dict[str, Union[Primitive, list[Union[Primitive,
dict[str, object], list[object]]], dict[object, object]]],
coordinate_post_data: dict[str, object]
) -> None:
"""
Test step to validate keys, values and data types from coordinates 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 coordinate_post_data: Fixture to get sample coordinate data and actual coordinate response.
"""
# validate coordinate keys from coordinates get response
logger.info("Accessing /coordinates endpoint through Traffic ops session.")

coordinate_name = coordinate_post_data.get("name")
if not isinstance(coordinate_name, str):
raise TypeError("malformed coordinate in prerequisite data; 'name' not a string")

coordinate_get_response: tuple[
Union[dict[str, object], list[Union[dict[str, object], list[object], Primitive]], Primitive],
requests.Response
] = to_session.get_coordinates(query_params={"name": coordinate_name})
try:
coordinate_data = coordinate_get_response[0]
if not isinstance(coordinate_data, list):
raise TypeError("malformed API response; 'response' property not an array")

first_coordinate = coordinate_data[0]
if not isinstance(first_coordinate, dict):
raise TypeError("malformed API response; first coordinate in response is not an dict")

logger.info("Coordinate Api response %s", first_coordinate)
coordinate_response_template = response_template_data.get("coordinates")
if not isinstance(coordinate_response_template, dict):
raise TypeError(
f"coordinate response template data must be a dict, not '{type(coordinate_response_template)}'")

# validate coordinate values from prereq data in coordinates get response.
keys = ["name", "latitude", "longitude"]
prereq_values = [coordinate_post_data[key] for key in keys]
get_values = [first_coordinate[key] for key in keys]

# validate keys, data types and values from coordinates get json response.
assert validate(instance=first_coordinate, schema=coordinate_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 coordinates endpoint: API response was malformed")
finally:
# Delete coordinate after test execution to avoid redundancy.
coordinate_id = coordinate_post_data.get("id")
if to_session.delete_coordinates(query_params={"id": coordinate_id}) is None:
logger.error("coordinate returned by Traffic Ops is missing a 'id' property")
pytest.fail("Response from delete request is empty, Failing test_coordinates_contract")

0 comments on commit 3bc814a

Please sign in to comment.