add api_adapter test

This commit is contained in:
Sosokker 2025-05-11 17:04:15 +07:00
parent 73654a402c
commit 5e24de9536
4 changed files with 162 additions and 0 deletions

View File

@ -10,6 +10,8 @@ dependencies = [
"inquirer>=3.4.0",
"loguru>=0.7.3",
"pandas>=2.2.3",
"pytest>=8.3.5",
"python-dotenv>=1.1.0",
"responses>=0.25.7",
"rich>=14.0.0",
]

0
tests/__init__.py Normal file
View File

109
tests/test_api_adapter.py Normal file
View File

@ -0,0 +1,109 @@
import responses
import pytest
from ingestion.adapters.api_adapter import ApiAdapter
import httpx
@pytest.fixture
def single_product():
return "https://dummyjson.com/products/1"
@pytest.fixture
def multiple_product():
return "https://dummyjson.com/products"
@pytest.fixture
def auth_endpoint():
return "https://dummyjson.com/auth/login"
@pytest.fixture
def auth_require_endpoint():
return "https://dummyjson.com/auth/me"
def test_fetch_dict_response(single_product):
"""Test fetching a single record from a JSON API endpoint."""
response = httpx.get(single_product, timeout=10)
response.raise_for_status()
expected_data = response.json()
assert isinstance(expected_data, dict)
adapter = ApiAdapter(url=single_product)
adapter_result = adapter.fetch()
assert isinstance(adapter_result, list)
assert adapter_result[0] == expected_data
def test_fetch_list_response(multiple_product):
"""Test fetching a list of records from a JSON API endpoint."""
response = httpx.get(multiple_product, timeout=10)
response.raise_for_status()
expected_data = response.json()
adapter = ApiAdapter(url=multiple_product)
adapter_result = adapter.fetch()
assert adapter_result[0] == expected_data
@responses.activate
def test_fetch_http_error(single_product):
"""Test handling HTTP errors and validate graceful failure."""
for _ in range(4):
responses.add(responses.GET, single_product, status=500)
adapter = ApiAdapter(url=single_product)
with pytest.raises(RuntimeError) as exc_info:
adapter.fetch()
assert "API request failed" in str(exc_info.value)
@responses.activate
def test_fetch_json_decode_error(single_product):
"""Test handling JSON decode errors."""
responses.add(responses.GET, single_product, body="not-a-json", status=200)
adapter = ApiAdapter(url=single_product)
with pytest.raises(RuntimeError) as exc_info:
adapter.fetch()
assert "Failed to parse JSON response" in str(exc_info.value)
def test_token_header_injection(auth_endpoint, auth_require_endpoint):
"""Test that the token is injected into the Authorization header."""
payload = {
"username": "emilys",
"password": "emilyspass",
"expiresInMins": 30
}
response = httpx.post(
auth_endpoint,
timeout=10,
headers={"Content-Type": "application/json"},
json=payload
)
response.raise_for_status()
assert response.status_code == 200
token = response.json().get("accessToken")
adapter = ApiAdapter(url=auth_require_endpoint, token=token)
adapter_result = adapter.fetch()
assert isinstance(adapter_result, list)
assert adapter_result[0].get("username") == "emilys"
def test_custom_headers_are_used(single_product):
"""Test that custom headers are used."""
headers = {"X-Custom-Header": "test-value"}
adapter = ApiAdapter(url=single_product, headers=headers)
assert adapter.headers.get("X-Custom-Header") == "test-value"

51
uv.lock
View File

@ -307,7 +307,9 @@ dependencies = [
{ name = "inquirer" },
{ name = "loguru" },
{ name = "pandas" },
{ name = "pytest" },
{ name = "python-dotenv" },
{ name = "responses" },
{ name = "rich" },
]
@ -318,7 +320,9 @@ requires-dist = [
{ name = "inquirer", specifier = ">=3.4.0" },
{ name = "loguru", specifier = ">=0.7.3" },
{ name = "pandas", specifier = ">=2.2.3" },
{ name = "pytest", specifier = ">=8.3.5" },
{ name = "python-dotenv", specifier = ">=1.1.0" },
{ name = "responses", specifier = ">=0.25.7" },
{ name = "rich", specifier = ">=14.0.0" },
]
@ -684,6 +688,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/79/9d/0fb148dc4d6fa4a7dd1d8378168d9b4cd8d4560a6fbf6f0121c5fc34eb68/importlib_metadata-8.6.1-py3-none-any.whl", hash = "sha256:02a89390c1e15fdfdc0d7c6b25cb3e62650d0494005c97d6f148bf5b9787525e", size = 26971 },
]
[[package]]
name = "iniconfig"
version = "2.1.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050 },
]
[[package]]
name = "inquirer"
version = "3.4.0"
@ -1152,6 +1165,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/20/0f/098488de02e3d52fc77e8d55c1467f6703701b6ea6788f40409bb8c00dd4/playwright-1.51.0-py3-none-win_amd64.whl", hash = "sha256:9ece9316c5d383aed1a207f079fc2d552fff92184f0ecf37cc596e912d00a8c3", size = 34862693 },
]
[[package]]
name = "pluggy"
version = "1.5.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 },
]
[[package]]
name = "propcache"
version = "0.3.1"
@ -1330,6 +1352,21 @@ version = "1.9.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/30/23/2f0a3efc4d6a32f3b63cdff36cd398d9701d26cda58e3ab97ac79fb5e60d/pyperclip-1.9.0.tar.gz", hash = "sha256:b7de0142ddc81bfc5c7507eea19da920b92252b548b96186caf94a5e2527d310", size = 20961 }
[[package]]
name = "pytest"
version = "8.3.5"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama", marker = "sys_platform == 'win32'" },
{ name = "iniconfig" },
{ name = "packaging" },
{ name = "pluggy" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ae/3c/c9d525a414d506893f0cd8a8d0de7706446213181570cdbd766691164e40/pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845", size = 1450891 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", size = 343634 },
]
[[package]]
name = "python-dateutil"
version = "2.9.0.post0"
@ -1483,6 +1520,20 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928 },
]
[[package]]
name = "responses"
version = "0.25.7"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pyyaml" },
{ name = "requests" },
{ name = "urllib3" },
]
sdist = { url = "https://files.pythonhosted.org/packages/81/7e/2345ac3299bd62bd7163216702bbc88976c099cfceba5b889f2a457727a1/responses-0.25.7.tar.gz", hash = "sha256:8ebae11405d7a5df79ab6fd54277f6f2bc29b2d002d0dd2d5c632594d1ddcedb", size = 79203 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e4/fc/1d20b64fa90e81e4fa0a34c9b0240a6cfb1326b7e06d18a5432a9917c316/responses-0.25.7-py3-none-any.whl", hash = "sha256:92ca17416c90fe6b35921f52179bff29332076bb32694c0df02dcac2c6bc043c", size = 34732 },
]
[[package]]
name = "rich"
version = "14.0.0"