Skip to content

Commit 03bb355

Browse files
authored
refactor: extract firmware check logic into a dedicated helper method to reduce duplication (#527)
* refactor: extract firmware check logic into a dedicated helper method to reduce duplication * handle JSON decode errors and non-dictionary responses from the GitHub API
1 parent f7cc8db commit 03bb355

2 files changed

Lines changed: 39 additions & 35 deletions

File tree

openevsehttp/__main__.py

Lines changed: 31 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -593,42 +593,11 @@ async def firmware_check(self) -> dict | None:
593593
return None
594594

595595
try:
596-
if self._session:
597-
session = self._session
598-
http_method = getattr(session, method)
599-
_LOGGER.debug(
600-
"Connecting to %s using method %s",
601-
url,
602-
method,
603-
)
604-
async with http_method(url) as resp:
605-
if resp.status != 200:
606-
return None
607-
message = await resp.text()
608-
message = json.loads(message)
609-
response = {}
610-
response["latest_version"] = message["tag_name"]
611-
response["release_notes"] = message["body"]
612-
response["release_url"] = message["html_url"]
613-
return response
614-
else:
596+
if (session := self._session) is None:
615597
async with aiohttp.ClientSession() as session:
616-
http_method = getattr(session, method)
617-
_LOGGER.debug(
618-
"Connecting to %s using method %s",
619-
url,
620-
method,
621-
)
622-
async with http_method(url) as resp:
623-
if resp.status != 200:
624-
return None
625-
message = await resp.text()
626-
message = json.loads(message)
627-
response = {}
628-
response["latest_version"] = message["tag_name"]
629-
response["release_notes"] = message["body"]
630-
response["release_url"] = message["html_url"]
631-
return response
598+
return await self._firmware_check_with_session(session, url, method)
599+
else:
600+
return await self._firmware_check_with_session(session, url, method)
632601

633602
except (TimeoutError, ServerTimeoutError):
634603
_LOGGER.error("%s: %s", ERROR_TIMEOUT, url)
@@ -639,6 +608,33 @@ async def firmware_check(self) -> dict | None:
639608

640609
return None
641610

611+
async def _firmware_check_with_session(
612+
self, session: aiohttp.ClientSession, url: str, method: str
613+
) -> dict | None:
614+
"""Process a firmware check request with a given session."""
615+
http_method = getattr(session, method)
616+
_LOGGER.debug(
617+
"Connecting to %s using method %s",
618+
url,
619+
method,
620+
)
621+
async with http_method(url) as resp:
622+
if resp.status != 200:
623+
return None
624+
message = await resp.text()
625+
try:
626+
message = json.loads(message)
627+
except json.JSONDecodeError:
628+
_LOGGER.error("Failed to parse JSON response: %s", message)
629+
return None
630+
631+
response = {}
632+
if isinstance(message, dict):
633+
response["latest_version"] = message.get("tag_name")
634+
response["release_notes"] = message.get("body")
635+
response["release_url"] = message.get("html_url")
636+
return response
637+
642638
def _version_check(self, min_version: str, max_version: str = "") -> bool:
643639
"""Return bool if minimum version is met."""
644640
if "version" not in self._config:

tests/test_main.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3174,6 +3174,14 @@ async def test_firmware_check_errors(mock_aioclient):
31743174
)
31753175
assert await charger.firmware_check() is None
31763176

3177+
# JSONDecodeError from github
3178+
mock_aioclient.get(url, status=200, body="not json")
3179+
assert await charger.firmware_check() is None
3180+
3181+
# Non-dict JSON from github
3182+
mock_aioclient.get(url, status=200, body='"just a string"')
3183+
assert await charger.firmware_check() == {}
3184+
31773185

31783186
async def test_websocket_pong():
31793187
"""Test websocket handles pong message."""

0 commit comments

Comments
 (0)