mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-24 13:01:56 +00:00
466f1a3d73
Co-authored-by: Hugo P.Brito <hugopbrit@gmail.com> Co-authored-by: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com>
153 lines
4.7 KiB
Python
153 lines
4.7 KiB
Python
"""Tests for the raw-JSON HTTP helpers in
|
|
`prowler.providers.okta.lib.service.raw_fetch`.
|
|
|
|
Covers `get_json` (single-shot) and `get_json_paginated`
|
|
(drains list endpoints via the `Link: rel="next"` cursor).
|
|
"""
|
|
|
|
import asyncio
|
|
import json
|
|
from unittest import mock
|
|
|
|
from prowler.providers.okta.lib.service.raw_fetch import (
|
|
get_json,
|
|
get_json_paginated,
|
|
)
|
|
|
|
|
|
def _run(coro):
|
|
return asyncio.run(coro)
|
|
|
|
|
|
def _mock_response(headers: dict = None):
|
|
r = mock.MagicMock()
|
|
r.headers = headers or {}
|
|
return r
|
|
|
|
|
|
class Test_get_json:
|
|
def test_returns_parsed_json_on_success(self):
|
|
client = mock.MagicMock()
|
|
|
|
async def create(*_a, **_k):
|
|
return ({"url": "/x"}, None)
|
|
|
|
async def execute(_req):
|
|
return (_mock_response(), json.dumps({"hello": "world"}), None)
|
|
|
|
client._request_executor.create_request = create
|
|
client._request_executor.execute = execute
|
|
|
|
assert _run(get_json(client, "/x")) == {"hello": "world"}
|
|
|
|
def test_returns_none_on_create_request_error(self):
|
|
client = mock.MagicMock()
|
|
|
|
async def create(*_a, **_k):
|
|
return (None, Exception("boom"))
|
|
|
|
client._request_executor.create_request = create
|
|
assert _run(get_json(client, "/x")) is None
|
|
|
|
def test_returns_none_on_execute_error(self):
|
|
client = mock.MagicMock()
|
|
|
|
async def create(*_a, **_k):
|
|
return ({"url": "/x"}, None)
|
|
|
|
async def execute(_req):
|
|
return (_mock_response(), None, Exception("boom"))
|
|
|
|
client._request_executor.create_request = create
|
|
client._request_executor.execute = execute
|
|
assert _run(get_json(client, "/x")) is None
|
|
|
|
|
|
class Test_get_json_paginated:
|
|
def test_drains_all_pages_following_link_rel_next(self):
|
|
# Two pages: first carries `Link: <…?after=cur1>; rel="next"`,
|
|
# second has no `next`, so iteration stops.
|
|
client = mock.MagicMock()
|
|
|
|
page1 = [{"id": "a"}, {"id": "b"}]
|
|
page2 = [{"id": "c"}]
|
|
page1_headers = {
|
|
"link": '<https://acme.okta.com/api/v1/items?after=cur1>; rel="next"'
|
|
}
|
|
|
|
seen_urls = []
|
|
|
|
async def create(**kwargs):
|
|
seen_urls.append(kwargs["url"])
|
|
return ({"url": kwargs["url"]}, None)
|
|
|
|
async def execute(request):
|
|
if "after=cur1" in request["url"]:
|
|
return (_mock_response({}), json.dumps(page2), None)
|
|
return (_mock_response(page1_headers), json.dumps(page1), None)
|
|
|
|
client._request_executor.create_request = create
|
|
client._request_executor.execute = execute
|
|
|
|
items = _run(get_json_paginated(client, "/api/v1/items", page_size=2))
|
|
|
|
assert items == [{"id": "a"}, {"id": "b"}, {"id": "c"}]
|
|
assert len(seen_urls) == 2
|
|
assert "limit=2" in seen_urls[0]
|
|
# The cursor was carried into the second request.
|
|
assert "after=cur1" in seen_urls[1]
|
|
assert "limit=2" in seen_urls[1]
|
|
|
|
def test_single_page_terminates_immediately(self):
|
|
client = mock.MagicMock()
|
|
|
|
async def create(**kwargs):
|
|
return ({"url": kwargs["url"]}, None)
|
|
|
|
async def execute(_req):
|
|
return (_mock_response({}), json.dumps([{"id": "only"}]), None)
|
|
|
|
client._request_executor.create_request = create
|
|
client._request_executor.execute = execute
|
|
|
|
assert _run(get_json_paginated(client, "/api/v1/items")) == [{"id": "only"}]
|
|
|
|
def test_returns_none_when_response_is_not_a_list(self):
|
|
client = mock.MagicMock()
|
|
|
|
async def create(**kwargs):
|
|
return ({"url": kwargs["url"]}, None)
|
|
|
|
async def execute(_req):
|
|
return (_mock_response({}), json.dumps({"error": "nope"}), None)
|
|
|
|
client._request_executor.create_request = create
|
|
client._request_executor.execute = execute
|
|
|
|
assert _run(get_json_paginated(client, "/api/v1/items")) is None
|
|
|
|
def test_preserves_existing_query_string_and_overrides_limit(self):
|
|
# Caller already passes `type=USER_LIFECYCLE` — pagination must
|
|
# merge `limit` without clobbering existing params.
|
|
client = mock.MagicMock()
|
|
seen = []
|
|
|
|
async def create(**kwargs):
|
|
seen.append(kwargs["url"])
|
|
return ({"url": kwargs["url"]}, None)
|
|
|
|
async def execute(_req):
|
|
return (_mock_response({}), "[]", None)
|
|
|
|
client._request_executor.create_request = create
|
|
client._request_executor.execute = execute
|
|
|
|
_run(
|
|
get_json_paginated(
|
|
client, "/api/v1/policies?type=USER_LIFECYCLE", page_size=50
|
|
)
|
|
)
|
|
|
|
assert "type=USER_LIFECYCLE" in seen[0]
|
|
assert "limit=50" in seen[0]
|