diff --git a/schema_helpers.py b/schema_helpers.py new file mode 100644 index 0000000..e6cf81b --- /dev/null +++ b/schema_helpers.py @@ -0,0 +1,23 @@ +import jsonschema + +#created this file to place helper functions for cleaner code + +#helper function to validate pet schemas +def validate_schema(instance, schema): + try: + jsonschema.validate(instance=instance, schema=schema) + except jsonschema.ValidationError as e: + path = ".".join(str(p) for p in e.path) + raise AssertionError( + f"Schema validation error at '{path}': {e.message}" + ) from e + +#helper function to safely verify json +def safe_json(response): + if not response.content: + return None + + try: + return response.json() + except ValueError: + return None \ No newline at end of file diff --git a/schemas.py b/schemas.py index 946cb6c..c347416 100644 --- a/schemas.py +++ b/schemas.py @@ -5,8 +5,9 @@ "id": { "type": "integer" }, + #switched name type to string from integer to fix test 1 in test_pet.py "name": { - "type": "integer" + "type": "string" }, "type": { "type": "string", @@ -18,3 +19,28 @@ }, } } + +#defined new order schemas for use in test_store +order = { + "type": "object", + "required": ["pet_id"], + "properties": { + "id": { + "type": "string" + }, + "pet_id": { + "type": "integer" + } + } +} + + +order_update = { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": ["available", "sold", "pending"] + } + } +} diff --git a/test_pet.py b/test_pet.py index e215678..f382175 100644 --- a/test_pet.py +++ b/test_pet.py @@ -3,6 +3,9 @@ import schemas import api_helpers from hamcrest import assert_that, contains_string, is_ +#added imports for helper functions in a new helper file +import schema_helpers +from schema_helpers import safe_json ''' TODO: Finish this test by... @@ -26,7 +29,8 @@ def test_pet_schema(): 3) Validate the 'status' property in the response is equal to the expected status 4) Validate the schema for each object in the response ''' -@pytest.mark.parametrize("status", [("available")]) +#updated parameters to include all status params - added pending, sold +@pytest.mark.parametrize("status", ["available", "pending", "sold"]) def test_find_by_status_200(status): test_endpoint = "/pets/findByStatus" params = { @@ -34,13 +38,51 @@ def test_find_by_status_200(status): } response = api_helpers.get_api_data(test_endpoint, params) - # TODO... + + #validate appropriate response code + assert response.status_code == 200 + + response_json = response.json() + + #response should be a list + assert isinstance(response_json, list) + + for pet in response_json: + #validate the status property + assert pet["status"] == status + + #validating schema for each object + schema_helpers.validate_schema( + instance=pet, + schema=schemas.pet + ) + ''' TODO: Finish this test by... 1) Testing and validating the appropriate 404 response for /pets/{pet_id} 2) Parameterizing the test for any edge cases ''' -def test_get_by_id_404(): - # TODO... - pass \ No newline at end of file +#parameterizing the edge cases +@pytest.mark.parametrize( + "pet_id, expected_status", + [ + (0, 200), # API treats 0 as valid + (-1, 404), # invalid ID, no body + (999999999, 404), # non-existent + ("invalid", 404), # invalid type + ] +) +def test_get_by_id_404(pet_id, expected_status): + response = api_helpers.get_api_data(f"/pets/{pet_id}") + + #validate response code + assert response.status_code == expected_status + + #safely validate error body if present + if expected_status == 404: + body = safe_json(response) + + #API may or may not return a body, valid either way + if body is not None: + assert "message" in body \ No newline at end of file diff --git a/test_store.py b/test_store.py index 186bd79..90df5bd 100644 --- a/test_store.py +++ b/test_store.py @@ -1,8 +1,13 @@ -from jsonschema import validate import pytest -import schemas -import api_helpers -from hamcrest import assert_that, contains_string, is_ +import requests +import random +import schema_helpers +from schemas import pet, order, order_update # assumes your schemas.py has order and order_update +import schema_helpers +from schema_helpers import safe_json +import string + +BASE_URL = "http://127.0.0.1:5000/" # Replace with your API base URL ''' TODO: Finish this test by... @@ -12,5 +17,67 @@ 3) Validate the response codes and values 4) Validate the response message "Order and pet status updated successfully" ''' -def test_patch_order_by_id(): - pass + +@pytest.fixture +def create_random_order(): + #create a random pet + pet_id = random.randint(1000, 99999) + pet_name = "pet_" + "".join(random.choices(string.ascii_lowercase + string.digits, k=6)) + pet_data = { + "id": pet_id, + "name": pet_name, + "type": "cat", + "status": "available" + } + + resp_pet = requests.post(f"{BASE_URL}/pets", json=pet_data) + assert resp_pet.status_code in (200, 201), f"Pet creation failed: {resp_pet.content}" + + #create a random order for this pet + order_id = "order_" + "".join(random.choices(string.digits, k=5)) + order_data = { + "id": order_id, + "pet_id": pet_id + } + + resp_order = requests.post(f"{BASE_URL}/store/order", json=order_data) + assert resp_order.status_code in (200, 201), f"Order creation failed: {resp_order.content}" + + #validate order schema + order_schema = { + "type": "object", + "required": ["pet_id"], + "properties": { + "id": {"type": "string"}, + "pet_id": {"type": "integer"} + } + } + schema_helpers.validate_schema(resp_order.json(), order_schema) + + yield order_id, pet_id + + #delete the order and pet + requests.delete(f"{BASE_URL}/store/order/{order_id}") + requests.delete(f"{BASE_URL}/pets/{pet_id}") + + +def test_patch_order_to_available(create_random_order): + + order_id, pet_id = create_random_order + patch_data = {"status": "available"} + + #send PATCH request + #NOTE: this line quietly fails, unsure of cause + resp = requests.patch(f"{BASE_URL}/store/order/{order_id}", json=patch_data) + assert resp.status_code == 200, f"PATCH failed: {resp.content}" + + resp_json = resp.json() + + #validate message + assert resp_json.get("message") == "Order and pet status updated successfully" + + #validate schema + schema_helpers.validate_schema(resp_json, order_update) + + #validate updated status + assert resp_json.get("status") == "available" \ No newline at end of file