Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/ipsdk/platform.py
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,15 @@ async def authenticate_oauth(self) -> None:
res = await self.client.post(path, headers=headers, data=data)
res.raise_for_status()

# Parse the response to extract the token
response_data = jsonutils.loads(res.text)
if isinstance(response_data, dict):
access_token = response_data.get("access_token")
else:
access_token = None

self.token = access_token

except httpx.HTTPStatusError as exc:
logging.exception(exc)
raise exceptions.HTTPStatusError(exc.message, exc)
Expand Down
55 changes: 53 additions & 2 deletions tests/test_platform.py
Original file line number Diff line number Diff line change
Expand Up @@ -618,8 +618,12 @@ async def test_async_authenticate_oauth_success():
mock_response.raise_for_status = Mock()
mixin.client.post.return_value = mock_response

await mixin.authenticate_oauth()
with patch(
"ipsdk.jsonutils.loads", return_value={"access_token": "async_token_123"}
):
await mixin.authenticate_oauth()

assert mixin.token == "async_token_123"
# Verify the post was called with correct params
mixin.client.post.assert_awaited_once_with(
"/oauth/token",
Expand Down Expand Up @@ -678,6 +682,48 @@ async def test_async_authenticate_oauth_request_error():
await mixin.authenticate_oauth()


@pytest.mark.asyncio
async def test_async_authenticate_oauth_no_access_token():
"""Test async authenticate_oauth when response has no access_token."""
mixin = AsyncAuthMixin()
mixin.client_id = "test_id"
mixin.client_secret = "test_secret"
mixin.client = AsyncMock()

# Mock response without access_token
mock_response = Mock(spec=Response)
mock_response.text = '{"error": "invalid_grant"}'
mock_response.raise_for_status = Mock()
mixin.client.post.return_value = mock_response

with patch("ipsdk.jsonutils.loads", return_value={"error": "invalid_grant"}):
await mixin.authenticate_oauth()

# Token should be None when access_token is missing
assert mixin.token is None


@pytest.mark.asyncio
async def test_async_authenticate_oauth_non_dict_response():
"""Test async authenticate_oauth when response is not a dict."""
mixin = AsyncAuthMixin()
mixin.client_id = "test_id"
mixin.client_secret = "test_secret"
mixin.client = AsyncMock()

# Mock response that parses to a list instead of dict
mock_response = Mock(spec=Response)
mock_response.text = '["invalid", "response"]'
mock_response.raise_for_status = Mock()
mixin.client.post.return_value = mock_response

with patch("ipsdk.jsonutils.loads", return_value=["invalid", "response"]):
await mixin.authenticate_oauth()

# Token should be None when response is not a dict
assert mixin.token is None


@pytest.mark.asyncio
async def test_async_authenticate_basicauth_http_status_error():
"""Test async authenticate_basicauth raises TypeError due to bug."""
Expand Down Expand Up @@ -753,11 +799,16 @@ async def test_async_authenticate_oauth_path():
# Mock successful response
mock_response = Mock()
mock_response.status_code = 200
mock_response.text = '{"access_token": "test_token_123"}'
mock_response.raise_for_status = Mock()
mixin.client.post.return_value = mock_response

await mixin.authenticate()
with patch(
"ipsdk.jsonutils.loads", return_value={"access_token": "test_token_123"}
):
await mixin.authenticate()

assert mixin.token == "test_token_123"
# Verify OAuth was called
mixin.client.post.assert_awaited_once_with(
"/oauth/token",
Expand Down