Skip to content

Commit a7d3d41

Browse files
authored
Fix plugin check and plugin removal wording (#495)
* Fix plugin check * Improve plugin removed wording * Fix tests
1 parent 80e2e9e commit a7d3d41

File tree

4 files changed

+50
-29
lines changed

4 files changed

+50
-29
lines changed

custom_components/opnsense/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ async def _deprecated_plugin_cleanup_26_1_1(
394394
if cleanup_started:
395395
if plugin_installed:
396396
_LOGGER.info(
397-
"OPNsense 26.1.1 and Plugin cleanup partially completed. Plugin is still installed. NAT Outbound and NAT Port Forward rules removed. Firewall Filter rules will be removed once the plugin is removed."
397+
"OPNsense 26.1.1 and Plugin cleanup partially completed. OPNsense Plugin is still installed. NAT Outbound and NAT Port Forward rules removed. Firewall Filter rules will be removed once the plugin is removed."
398398
)
399399
ir.async_create_issue(
400400
hass,
@@ -408,7 +408,7 @@ async def _deprecated_plugin_cleanup_26_1_1(
408408
)
409409
else:
410410
_LOGGER.info(
411-
"OPNsense 26.1.1 and Plugin cleanup completed. NAT Outbound, NAT Port Forward, and Firewall Filter rules removed."
411+
"OPNsense 26.1.1 and Plugin cleanup completed. OPNsense Plugin is not installed. NAT Outbound, NAT Port Forward, and Firewall Filter rules removed."
412412
)
413413
ir.async_create_issue(
414414
hass,

custom_components/opnsense/pyopnsense/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ async def is_plugin_installed(self) -> bool:
349349
if not isinstance(firmware_info.get("package"), list):
350350
return False
351351
for pkg in firmware_info.get("package", []):
352-
if pkg.get("name") == "os-homeassistant-maxit":
352+
if pkg.get("name") == "os-homeassistant-maxit" and pkg.get("installed") == "1":
353353
return True
354354
return False
355355

custom_components/opnsense/translations/en.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@
123123
},
124124
"plugin_cleanup_done": {
125125
"title": "OPNsense 26.1.1 and Plugin cleanup completed",
126-
"description": "NAT Outbound, NAT Port Forward, and Firewall Filter rules removed."
126+
"description": "OPNsense Plugin is not installed. NAT Outbound, NAT Port Forward, and Firewall Filter rules removed."
127127
}
128128
},
129129
"selector": {

tests/test_pyopnsense.py

Lines changed: 46 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -264,30 +264,43 @@ async def test_opnsenseclient_async_close(make_client) -> None:
264264

265265

266266
@pytest.mark.asyncio
267-
async def test_get_host_firmware_set_use_snake_case_and_plugin_installed(
268-
monkeypatch, make_client
269-
) -> None:
270-
"""Ensure firmware parsing, snake_case detection and plugin detection work."""
271-
# create client/session for this test
267+
async def test_get_host_firmware_version_and_fallback(make_client) -> None:
268+
"""Verify get_host_firmware_version returns product_version when valid and falls back to product_series."""
272269
session = MagicMock(spec=aiohttp.ClientSession)
273270
client = make_client(session=session)
274271

275-
# firmware valid semver
272+
# valid semver
276273
client._safe_dict_get = AsyncMock(return_value={"product": {"product_version": "25.8.0"}})
277274
fw = await client.get_host_firmware_version()
278275
assert fw == "25.8.0"
279276

280-
# set use snake case should detect >=25.7
281-
client._firmware_version = "25.8.0"
282-
await client.set_use_snake_case()
283-
assert client._use_snake_case is True
277+
# invalid semver -> fallback to product_series
278+
client._safe_dict_get = AsyncMock(
279+
return_value={"product": {"product_version": "weird", "product_series": "seriesX"}}
280+
)
281+
fw2 = await client.get_host_firmware_version()
282+
assert fw2 == "seriesX"
283+
await client.async_close()
284+
284285

285-
# set use snake case should detect <25.7
286-
client._firmware_version = "25.1.0"
286+
@pytest.mark.asyncio
287+
@pytest.mark.parametrize("firmware,expected", [("25.8.0", True), ("25.1.0", False)])
288+
async def test_set_use_snake_case_detection(make_client, firmware, expected) -> None:
289+
"""set_use_snake_case should detect firmware ranges correctly."""
290+
session = MagicMock(spec=aiohttp.ClientSession)
291+
client = make_client(session=session)
292+
client._firmware_version = firmware
287293
await client.set_use_snake_case()
288-
assert client._use_snake_case is False
294+
assert client._use_snake_case is expected
295+
await client.async_close()
296+
297+
298+
@pytest.mark.asyncio
299+
async def test_set_use_snake_case_handles_compare_exception(monkeypatch, make_client) -> None:
300+
"""set_use_snake_case should default to snake_case True on comparison exception."""
301+
session = MagicMock(spec=aiohttp.ClientSession)
302+
client = make_client(session=session)
289303

290-
# test AwesomeVersionCompareException handling
291304
def mock_compare(self, other):
292305
raise awesomeversion.exceptions.AwesomeVersionCompareException("test exception")
293306

@@ -297,18 +310,26 @@ def mock_compare(self, other):
297310
# Should default to True on exception
298311
assert client._use_snake_case is True
299312

300-
# invalid semver -> fallback to product_series
301-
client._safe_dict_get = AsyncMock(
302-
return_value={"product": {"product_version": "weird", "product_series": "seriesX"}}
303-
)
304-
fw2 = await client.get_host_firmware_version()
305-
assert fw2 == "seriesX"
306313

307-
# is_plugin_installed when package list present
308-
client._safe_dict_get = AsyncMock(
309-
return_value={"package": [{"name": "os-homeassistant-maxit"}]}
310-
)
311-
assert await client.is_plugin_installed() is True
314+
@pytest.mark.asyncio
315+
@pytest.mark.parametrize(
316+
"package_list,expected",
317+
[
318+
({"package": [{"name": "os-homeassistant-maxit", "installed": "1"}]}, True),
319+
({"package": [{"name": "os-homeassistant-maxit", "installed": "0"}]}, False),
320+
({}, False),
321+
({"package": [{"name": "some-other", "installed": "1"}]}, False),
322+
],
323+
)
324+
async def test_is_plugin_installed_various(make_client, package_list, expected) -> None:
325+
"""Parameterize plugin installation detection for several package list shapes."""
326+
session = MagicMock(spec=aiohttp.ClientSession)
327+
client = make_client(session=session)
328+
try:
329+
client._safe_dict_get = AsyncMock(return_value=package_list)
330+
assert await client.is_plugin_installed() is expected
331+
finally:
332+
await client.async_close()
312333

313334

314335
@pytest.mark.asyncio

0 commit comments

Comments
 (0)