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
78 changes: 78 additions & 0 deletions tests/test_device_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import pytest
from unittest.mock import AsyncMock, MagicMock, patch

from tplinkcloud.device_client import TPLinkDeviceClient


class TestPassThroughRequest:

@pytest.mark.asyncio
async def test_pass_through_request_handles_string_response_data(self):
"""Test that string responseData is parsed as JSON"""
client = TPLinkDeviceClient(
host='http://test.example.com',
token='test_token'
)

mock_response = MagicMock()
mock_response.successful = True
mock_response.result = {
'responseData': '{"system": {"get_sysinfo": {"relay_state": 1}}}'
}

with patch.object(client, '_request_post', new_callable=AsyncMock) as mock_post:
mock_post.return_value = mock_response
result = await client.pass_through_request(
'device123',
{'system': {'get_sysinfo': {}}}
)

assert result == {'system': {'get_sysinfo': {'relay_state': 1}}}

@pytest.mark.asyncio
async def test_pass_through_request_handles_dict_response_data(self):
"""
Test that dict responseData is returned as-is.
Some devices (e.g., Archer routers) return responseData as a dict
instead of a JSON string. Regression test for issue #65.
"""
client = TPLinkDeviceClient(
host='http://test.example.com',
token='test_token'
)

mock_response = MagicMock()
mock_response.successful = True
# responseData is already a dict, not a JSON string
mock_response.result = {
'responseData': {'system': {'get_sysinfo': {'relay_state': 1}}}
}

with patch.object(client, '_request_post', new_callable=AsyncMock) as mock_post:
mock_post.return_value = mock_response
result = await client.pass_through_request(
'device123',
{'system': {'get_sysinfo': {}}}
)

assert result == {'system': {'get_sysinfo': {'relay_state': 1}}}

@pytest.mark.asyncio
async def test_pass_through_request_returns_none_on_failure(self):
"""Test that None is returned when request fails"""
client = TPLinkDeviceClient(
host='http://test.example.com',
token='test_token'
)

mock_response = MagicMock()
mock_response.successful = False

with patch.object(client, '_request_post', new_callable=AsyncMock) as mock_post:
mock_post.return_value = mock_response
result = await client.pass_through_request(
'device123',
{'system': {'get_sysinfo': {}}}
)

assert result is None
7 changes: 6 additions & 1 deletion tplinkcloud/device_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ async def pass_through_request(self, device_id, request_data):
}
response = await self._request_post(body)
if response.successful:
return json.loads(response.result.get('responseData'))
response_data = response.result.get('responseData')
# Some devices (e.g., Archer routers) return responseData as a dict
# while others return it as a JSON string
if isinstance(response_data, str):
return json.loads(response_data)
return response_data

return None