Skip to content

Commit f0a28ef

Browse files
committed
bbox: add tests
1 parent f54864a commit f0a28ef

File tree

7 files changed

+431
-17
lines changed

7 files changed

+431
-17
lines changed

CODEOWNERS

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

homeassistant/components/bbox/device_tracker.py

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import logging
88

99
import pybbox
10+
import requests
1011
import voluptuous as vol
1112

1213
from homeassistant.components.device_tracker import (
@@ -78,21 +79,30 @@ def _update_info(self):
7879
"""
7980
_LOGGER.debug("Scanning")
8081

81-
box = pybbox.Bbox(ip=self.host)
82-
result = box.get_all_connected_devices()
83-
84-
now = dt_util.now()
85-
last_results = []
86-
for device in result:
87-
if device["active"] != 1:
88-
continue
89-
last_results.append(
90-
Device(
91-
device["macaddress"], device["hostname"], device["ipaddress"], now
82+
try:
83+
box = pybbox.Bbox(ip=self.host)
84+
result = box.get_all_connected_devices()
85+
86+
now = dt_util.now()
87+
last_results = []
88+
for device in result:
89+
if device["active"] != 1:
90+
continue
91+
last_results.append(
92+
Device(
93+
device["macaddress"],
94+
device["hostname"],
95+
device["ipaddress"],
96+
now,
97+
)
9298
)
93-
)
9499

95-
self.last_results = last_results
100+
self.last_results = last_results
96101

97-
_LOGGER.debug("Scan successful")
98-
return True
102+
_LOGGER.debug("Scan successful")
103+
except requests.exceptions.HTTPError as err:
104+
_LOGGER.error("Error scanning devices: %s", err)
105+
self.last_results = []
106+
else:
107+
return True
108+
return False
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
{
22
"domain": "bbox",
33
"name": "Bbox",
4-
"codeowners": [],
4+
"codeowners": ["@sweenu"],
55
"documentation": "https://www.home-assistant.io/integrations/bbox",
66
"iot_class": "local_polling",
7-
"loggers": ["pybbox"],
87
"quality_scale": "legacy",
98
"requirements": ["pybbox==0.0.5-alpha"]
109
}

requirements_test_all.txt

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/components/bbox/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Tests for the Bbox component."""
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
"""Tests for the Bbox device tracker platform."""
2+
3+
from unittest.mock import MagicMock, patch
4+
5+
import pytest
6+
import requests
7+
8+
from homeassistant.components.bbox.device_tracker import (
9+
PLATFORM_SCHEMA,
10+
BboxDeviceScanner,
11+
Device,
12+
get_scanner,
13+
)
14+
from homeassistant.components.device_tracker import DOMAIN as DEVICE_TRACKER_DOMAIN
15+
from homeassistant.core import HomeAssistant
16+
from homeassistant.helpers.typing import ConfigType
17+
18+
19+
@pytest.fixture
20+
def mock_bbox_api():
21+
"""Mock the pybbox API."""
22+
with patch("homeassistant.components.bbox.device_tracker.pybbox") as mock_pybbox:
23+
mock_box = MagicMock()
24+
mock_pybbox.Bbox.return_value = mock_box
25+
yield mock_box
26+
27+
28+
@pytest.fixture
29+
def device_tracker_config():
30+
"""Return device tracker configuration."""
31+
return {DEVICE_TRACKER_DOMAIN: {"host": "192.168.1.254"}}
32+
33+
34+
async def test_get_scanner_success(
35+
hass: HomeAssistant, device_tracker_config: ConfigType, mock_bbox_api
36+
) -> None:
37+
"""Test successful scanner initialization."""
38+
mock_bbox_api.get_all_connected_devices.return_value = [
39+
{
40+
"macaddress": "aa:bb:cc:dd:ee:ff",
41+
"hostname": "test_device",
42+
"ipaddress": "192.168.1.100",
43+
"active": 1,
44+
}
45+
]
46+
47+
scanner = get_scanner(hass, device_tracker_config)
48+
assert scanner is not None
49+
assert scanner.success_init is True
50+
51+
52+
async def test_get_scanner_failure(
53+
hass: HomeAssistant, device_tracker_config: ConfigType, mock_bbox_api
54+
) -> None:
55+
"""Test scanner initialization failure."""
56+
mock_bbox_api.get_all_connected_devices.side_effect = requests.exceptions.HTTPError(
57+
"Connection failed"
58+
)
59+
60+
# The scanner should return None when initialization fails
61+
# We need to patch the scanner initialization to handle the exception
62+
with patch.object(BboxDeviceScanner, "_update_info", return_value=False):
63+
scanner = get_scanner(hass, device_tracker_config)
64+
assert scanner is None
65+
66+
67+
async def test_scan_devices(
68+
hass: HomeAssistant, device_tracker_config: ConfigType
69+
) -> None:
70+
"""Test scanning for devices."""
71+
with patch.object(BboxDeviceScanner, "_update_info") as mock_update:
72+
# Create scanner without calling __init__ to avoid API calls
73+
scanner = BboxDeviceScanner.__new__(BboxDeviceScanner)
74+
scanner.host = device_tracker_config[DEVICE_TRACKER_DOMAIN]["host"]
75+
scanner.success_init = True
76+
scanner.last_results = [
77+
Device("aa:bb:cc:dd:ee:ff", "test_device", "192.168.1.100", None)
78+
]
79+
80+
devices = scanner.scan_devices()
81+
assert devices == ["aa:bb:cc:dd:ee:ff"]
82+
mock_update.assert_called_once()
83+
84+
85+
async def test_get_device_name(
86+
hass: HomeAssistant, device_tracker_config: ConfigType
87+
) -> None:
88+
"""Test getting device name by MAC address."""
89+
# Create scanner without calling __init__ to avoid API calls
90+
scanner = BboxDeviceScanner.__new__(BboxDeviceScanner)
91+
scanner.host = device_tracker_config[DEVICE_TRACKER_DOMAIN]["host"]
92+
scanner.success_init = True
93+
scanner.last_results = [
94+
Device("aa:bb:cc:dd:ee:ff", "test_device", "192.168.1.100", None),
95+
Device("ff:ee:dd:cc:bb:aa", "another_device", "192.168.1.101", None),
96+
]
97+
98+
# Test existing device
99+
name = scanner.get_device_name("aa:bb:cc:dd:ee:ff")
100+
assert name == "test_device"
101+
102+
# Test non-existing device
103+
name = scanner.get_device_name("11:22:33:44:55:66")
104+
assert name is None
105+
106+
107+
async def test_update_info_success(
108+
hass: HomeAssistant, device_tracker_config: ConfigType
109+
) -> None:
110+
"""Test successful device info update."""
111+
with patch("homeassistant.components.bbox.device_tracker.pybbox") as mock_pybbox:
112+
mock_box = MagicMock()
113+
mock_pybbox.Bbox.return_value = mock_box
114+
mock_box.get_all_connected_devices.return_value = [
115+
{
116+
"macaddress": "aa:bb:cc:dd:ee:ff",
117+
"hostname": "test_device",
118+
"ipaddress": "192.168.1.100",
119+
"active": 1,
120+
},
121+
{
122+
"macaddress": "ff:ee:dd:cc:bb:aa",
123+
"hostname": "inactive_device",
124+
"ipaddress": "192.168.1.101",
125+
"active": 0, # Should be filtered out
126+
},
127+
]
128+
129+
# Create scanner without calling __init__ to avoid API calls
130+
scanner = BboxDeviceScanner.__new__(BboxDeviceScanner)
131+
scanner.host = device_tracker_config[DEVICE_TRACKER_DOMAIN]["host"]
132+
scanner.success_init = True
133+
scanner.last_results = []
134+
135+
scanner._update_info()
136+
137+
# _update_info doesn't return a value on success, just updates last_results
138+
assert len(scanner.last_results) == 1
139+
device = scanner.last_results[0]
140+
assert device.mac == "aa:bb:cc:dd:ee:ff"
141+
assert device.name == "test_device"
142+
assert device.ip == "192.168.1.100"
143+
144+
145+
async def test_update_info_failure(
146+
hass: HomeAssistant, device_tracker_config: ConfigType
147+
) -> None:
148+
"""Test device info update failure."""
149+
with patch("homeassistant.components.bbox.device_tracker.pybbox") as mock_pybbox:
150+
mock_box = MagicMock()
151+
mock_pybbox.Bbox.return_value = mock_box
152+
mock_box.get_all_connected_devices.side_effect = requests.exceptions.HTTPError(
153+
"API Error"
154+
)
155+
156+
# Create scanner without calling __init__ to avoid API calls
157+
scanner = BboxDeviceScanner.__new__(BboxDeviceScanner)
158+
scanner.host = device_tracker_config[DEVICE_TRACKER_DOMAIN]["host"]
159+
scanner.success_init = True
160+
scanner.last_results = [Device("existing", "device", "192.168.1.100", None)]
161+
162+
# _update_info now properly handles exceptions and returns False
163+
result = scanner._update_info()
164+
165+
# On failure, _update_info should return False and clear last_results
166+
assert result is False
167+
assert scanner.last_results == []
168+
169+
170+
async def test_platform_schema() -> None:
171+
"""Test platform schema validation."""
172+
# Test default host - the schema expects platform config at top level, not nested
173+
config = {"platform": "bbox", "host": "192.168.1.254"}
174+
validated = PLATFORM_SCHEMA(config)
175+
assert validated["host"] == "192.168.1.254"
176+
177+
# Test custom host
178+
config = {"platform": "bbox", "host": "192.168.2.1"}
179+
validated = PLATFORM_SCHEMA(config)
180+
assert validated["host"] == "192.168.2.1"

0 commit comments

Comments
 (0)