2024-01-19 20:06:50 +00:00
|
|
|
import re
|
|
|
|
|
|
|
|
import aiohttp
|
|
|
|
import pytest
|
|
|
|
|
2024-11-11 10:11:31 +00:00
|
|
|
from kasa.deviceconfig import DeviceConfig
|
|
|
|
from kasa.exceptions import (
|
2024-02-21 15:52:55 +00:00
|
|
|
KasaException,
|
|
|
|
TimeoutError,
|
|
|
|
_ConnectionError,
|
2024-01-19 20:06:50 +00:00
|
|
|
)
|
2024-11-11 10:11:31 +00:00
|
|
|
from kasa.httpclient import HttpClient
|
2024-01-19 20:06:50 +00:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
2024-08-30 15:30:07 +00:00
|
|
|
("error", "error_raises", "error_message"),
|
2024-01-19 20:06:50 +00:00
|
|
|
[
|
|
|
|
(
|
|
|
|
aiohttp.ServerDisconnectedError(),
|
2024-02-21 15:52:55 +00:00
|
|
|
_ConnectionError,
|
2024-01-23 22:15:18 +00:00
|
|
|
"Device connection error: ",
|
2024-01-19 20:06:50 +00:00
|
|
|
),
|
|
|
|
(
|
|
|
|
aiohttp.ClientOSError(),
|
2024-02-21 15:52:55 +00:00
|
|
|
_ConnectionError,
|
2024-01-23 22:15:18 +00:00
|
|
|
"Device connection error: ",
|
2024-01-19 20:06:50 +00:00
|
|
|
),
|
|
|
|
(
|
|
|
|
aiohttp.ServerTimeoutError(),
|
2024-02-21 15:52:55 +00:00
|
|
|
TimeoutError,
|
2024-01-19 20:06:50 +00:00
|
|
|
"Unable to query the device, timed out: ",
|
|
|
|
),
|
|
|
|
(
|
2024-11-18 18:46:36 +00:00
|
|
|
TimeoutError(),
|
2024-02-21 15:52:55 +00:00
|
|
|
TimeoutError,
|
2024-01-19 20:06:50 +00:00
|
|
|
"Unable to query the device, timed out: ",
|
|
|
|
),
|
2024-02-21 15:52:55 +00:00
|
|
|
(Exception(), KasaException, "Unable to query the device: "),
|
2024-01-19 20:06:50 +00:00
|
|
|
(
|
2024-06-19 13:07:59 +00:00
|
|
|
aiohttp.ServerFingerprintMismatch(b"exp", b"got", "host", 1),
|
2024-02-21 15:52:55 +00:00
|
|
|
KasaException,
|
2024-01-19 20:06:50 +00:00
|
|
|
"Unable to query the device: ",
|
|
|
|
),
|
|
|
|
],
|
|
|
|
ids=(
|
|
|
|
"ServerDisconnectedError",
|
|
|
|
"ClientOSError",
|
|
|
|
"ServerTimeoutError",
|
|
|
|
"TimeoutError",
|
|
|
|
"Exception",
|
|
|
|
"ServerFingerprintMismatch",
|
|
|
|
),
|
|
|
|
)
|
2024-08-30 15:30:07 +00:00
|
|
|
@pytest.mark.parametrize("mock_read", [False, True], ids=("post", "read"))
|
2024-01-19 20:06:50 +00:00
|
|
|
async def test_httpclient_errors(mocker, error, error_raises, error_message, mock_read):
|
|
|
|
class _mock_response:
|
|
|
|
def __init__(self, status, error):
|
|
|
|
self.status = status
|
|
|
|
self.error = error
|
|
|
|
self.call_count = 0
|
|
|
|
|
|
|
|
async def __aenter__(self):
|
|
|
|
return self
|
|
|
|
|
|
|
|
async def __aexit__(self, exc_t, exc_v, exc_tb):
|
|
|
|
pass
|
|
|
|
|
|
|
|
async def read(self):
|
|
|
|
self.call_count += 1
|
|
|
|
raise self.error
|
|
|
|
|
|
|
|
mock_response = _mock_response(200, error)
|
|
|
|
|
|
|
|
async def _post(url, *_, **__):
|
|
|
|
nonlocal mock_response
|
|
|
|
return mock_response
|
|
|
|
|
|
|
|
host = "127.0.0.1"
|
|
|
|
|
|
|
|
side_effect = _post if mock_read else error
|
|
|
|
|
|
|
|
conn = mocker.patch.object(aiohttp.ClientSession, "post", side_effect=side_effect)
|
|
|
|
client = HttpClient(DeviceConfig(host))
|
|
|
|
# Exceptions with parameters print with double quotes, without use single quotes
|
|
|
|
full_msg = (
|
2024-06-19 13:07:59 +00:00
|
|
|
re.escape("(")
|
2024-01-19 20:06:50 +00:00
|
|
|
+ "['\"]"
|
|
|
|
+ re.escape(f"{error_message}{host}: {error}")
|
|
|
|
+ "['\"]"
|
|
|
|
+ re.escape(f", {repr(error)})")
|
|
|
|
)
|
|
|
|
with pytest.raises(error_raises, match=error_message) as exc_info:
|
|
|
|
await client.post("http://foobar")
|
|
|
|
|
|
|
|
assert re.match(full_msg, str(exc_info.value))
|
|
|
|
if mock_read:
|
|
|
|
assert mock_response.call_count == 1
|
|
|
|
else:
|
|
|
|
assert conn.call_count == 1
|