Skip to content

Commit d85b4e1

Browse files
committed
chore: add tests
1 parent fe661a5 commit d85b4e1

File tree

2 files changed

+108
-14
lines changed

2 files changed

+108
-14
lines changed

roborock/web_api.py

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@
3030
)
3131

3232
_LOGGER = logging.getLogger(__name__)
33+
BASE_URLS = [
34+
"https://usiot.roborock.com",
35+
"https://euiot.roborock.com",
36+
"https://cniot.roborock.com",
37+
"https://ruiot.roborock.com",
38+
]
3339

3440

3541
@dataclass
@@ -70,16 +76,7 @@ def __init__(
7076

7177
async def _get_iot_login_info(self) -> IotLoginInfo:
7278
if self._iot_login_info is None:
73-
valid_urls = (
74-
[
75-
"https://usiot.roborock.com",
76-
"https://euiot.roborock.com",
77-
"https://cniot.roborock.com",
78-
"https://ruiot.roborock.com",
79-
]
80-
if self._base_url is None
81-
else [self._base_url]
82-
)
79+
valid_urls = BASE_URLS if self._base_url is None else [self._base_url]
8380
for iot_url in valid_urls:
8481
url_request = PreparedRequest(iot_url, self.session)
8582
response = await url_request.request(
@@ -98,9 +95,7 @@ async def _get_iot_login_info(self) -> IotLoginInfo:
9895
"You are missing parameters for this request, are you sure you entered your username?"
9996
)
10097
else:
101-
_LOGGER.warning(
102-
"Failed to get base url for %s with the following context: %s", self._username, response
103-
)
98+
raise RoborockException(f"{response.get('msg')} - response code: {response_code}")
10499
if response["data"]["countrycode"] is not None:
105100
self._iot_login_info = IotLoginInfo(
106101
base_url=response["data"]["url"],

tests/test_web_api.py

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
import re
2+
13
import aiohttp
4+
from aioresponses.compat import normalize_url
25

36
from roborock import HomeData, HomeDataScene, UserData
4-
from roborock.web_api import RoborockApiClient
7+
from roborock.web_api import IotLoginInfo, RoborockApiClient
58
from tests.mock_data import HOME_DATA_RAW, USER_DATA
69

710

@@ -71,3 +74,99 @@ async def test_code_login_v4_flow(mock_rest) -> None:
7174
await api.request_code_v4()
7275
ud = await api.code_login_v4(4123, "US", 1)
7376
assert ud == UserData.from_dict(USER_DATA)
77+
78+
79+
async def test_url_cycling(mock_rest) -> None:
80+
"""Test that we cycle through the URLs correctly."""
81+
# Clear mock rest so that we can override the patches.
82+
mock_rest.clear()
83+
# 1. Mock US URL to return valid status but None for countrycode
84+
85+
mock_rest.post(
86+
re.compile("https://usiot.roborock.com/api/v1/getUrlByEmail.*"),
87+
status=200,
88+
payload={
89+
"code": 200,
90+
"data": {"url": "https://usiot.roborock.com", "country": None, "countrycode": None},
91+
"msg": "Success",
92+
},
93+
)
94+
95+
# 2. Mock EU URL to return a server-side error code
96+
mock_rest.post(
97+
re.compile("https://euiot.roborock.com/api/v1/getUrlByEmail.*"),
98+
status=200,
99+
payload={
100+
"code": 200,
101+
"data": {"url": "https://euiot.roborock.com", "country": None, "countrycode": None},
102+
"msg": "Success",
103+
},
104+
)
105+
106+
# 3. Mock CN URL to return the correct, valid data
107+
mock_rest.post(
108+
re.compile("https://cniot.roborock.com/api/v1/getUrlByEmail.*"),
109+
status=200,
110+
payload={
111+
"code": 200,
112+
"data": {"url": "https://cniot.roborock.com", "country": "CN", "countrycode": "86"},
113+
"msg": "Success",
114+
},
115+
)
116+
117+
# The RU URL should not be called, but we can mock it just in case
118+
# to catch unexpected behavior.
119+
mock_rest.post(re.compile("https://ruiot.roborock.com/api/v1/getUrlByEmail.*"), status=500)
120+
121+
client = RoborockApiClient("test@example.com")
122+
result = await client._get_iot_login_info()
123+
124+
assert result is not None
125+
assert isinstance(result, IotLoginInfo)
126+
assert result.base_url == "https://cniot.roborock.com"
127+
assert result.country == "CN"
128+
assert result.country_code == "86"
129+
130+
assert client._iot_login_info == result
131+
# Check that all three urls were called. We have to do this kind of weirdly as aioresponses seems to have a bug.
132+
assert (
133+
len(
134+
mock_rest.requests[
135+
(
136+
"post",
137+
normalize_url(
138+
"https://usiot.roborock.com/api/v1/getUrlByEmail?email=test%2540example.com&needtwostepauth=false"
139+
),
140+
)
141+
]
142+
)
143+
== 1
144+
)
145+
assert (
146+
len(
147+
mock_rest.requests[
148+
(
149+
"post",
150+
normalize_url(
151+
"https://euiot.roborock.com/api/v1/getUrlByEmail?email=test%2540example.com&needtwostepauth=false"
152+
),
153+
)
154+
]
155+
)
156+
== 1
157+
)
158+
assert (
159+
len(
160+
mock_rest.requests[
161+
(
162+
"post",
163+
normalize_url(
164+
"https://cniot.roborock.com/api/v1/getUrlByEmail?email=test%2540example.com&needtwostepauth=false"
165+
),
166+
)
167+
]
168+
)
169+
== 1
170+
)
171+
# Make sure we just have the three we tested for above.
172+
assert len(mock_rest.requests) == 3

0 commit comments

Comments
 (0)