Fix line length violations in tests/components g (#170882)

This commit is contained in:
Franck Nijhof
2026-05-16 17:06:36 +02:00
committed by GitHub
parent 3813843c8c
commit 5c29580969
59 changed files with 362 additions and 184 deletions
+4 -1
View File
@@ -111,7 +111,10 @@ async def test_garage_door_trigger_binary_sensor_behavior_any(
trigger_options: dict[str, Any],
states: list[TriggerStateDescription],
) -> None:
"""Test garage door trigger fires for binary_sensor entities with device_class garage_door."""
"""Test garage door trigger fires for binary_sensor entities.
Specifically for entities with device_class garage_door.
"""
await assert_trigger_behavior_any(
hass,
target_entities=target_binary_sensors,
@@ -102,9 +102,9 @@ async def scan_step(
def correct_scanners_and_clients_in_library(enable_bluetooth: None) -> Generator[None]:
"""Make sure the correct scanners and clients are used in the library.
This is needed since home assistant overrides the bleak scanner and client with wrappers,
but does so after enable_bluetooth fixture is applied, which causes the library to
use the wrong classes.
This is needed since home assistant overrides the bleak scanner and
client with wrappers, but does so after enable_bluetooth fixture is
applied, which causes the library to use the wrong classes.
"""
with (
patch("gardena_bluetooth.scan.BleakScanner", new=bleak.BleakScanner),
@@ -142,7 +142,11 @@ async def test_timeout_manufacturer_data(
scan_step: Callable[[], Awaitable[None]],
manufacturer_request_event: asyncio.Event,
) -> None:
"""Test the flow aborts with no_devices_found when manufacturer data times out and only partial info is available."""
"""Test the flow aborts with no_devices_found.
Specifically when manufacturer data times out and only partial info
is available.
"""
inject_bluetooth_service_info(hass, MISSING_PRODUCT_SERVICE_INFO)
+14 -14
View File
@@ -40,14 +40,14 @@ from tests.components.bluetooth import inject_bluetooth_service_info
WATER_TIMER_SERVICE_INFO,
{
Battery.battery_level.uuid: Battery.battery_level.encode(100),
DeviceInformation.model_number.uuid: DeviceInformation.model_number.encode(
"Model Number TBD"
DeviceInformation.model_number.uuid: (
DeviceInformation.model_number.encode("Model Number TBD")
),
DeviceInformation.firmware_version.uuid: DeviceInformation.firmware_version.encode(
"1.2.3"
DeviceInformation.firmware_version.uuid: (
DeviceInformation.firmware_version.encode("1.2.3")
),
DeviceConfiguration.custom_device_name.uuid: DeviceConfiguration.custom_device_name.encode(
"My timer"
DeviceConfiguration.custom_device_name.uuid: (
DeviceConfiguration.custom_device_name.encode("My timer")
),
},
id=WATER_TIMER_SERVICE_INFO.name,
@@ -55,17 +55,17 @@ from tests.components.bluetooth import inject_bluetooth_service_info
pytest.param(
AQUA_CONTOUR_SERVICE_INFO,
{
AquaContourBattery.battery_level.uuid: AquaContourBattery.battery_level.encode(
100
AquaContourBattery.battery_level.uuid: (
AquaContourBattery.battery_level.encode(100)
),
DeviceInformation.model_number.uuid: DeviceInformation.model_number.encode(
"Aqua Contour"
DeviceInformation.model_number.uuid: (
DeviceInformation.model_number.encode("Aqua Contour")
),
DeviceInformation.firmware_version.uuid: DeviceInformation.firmware_version.encode(
"2.0.0"
DeviceInformation.firmware_version.uuid: (
DeviceInformation.firmware_version.encode("2.0.0")
),
AquaContour.custom_device_name.uuid: AquaContour.custom_device_name.encode(
"My contour"
AquaContour.custom_device_name.uuid: (
AquaContour.custom_device_name.encode("My contour")
),
},
id=AQUA_CONTOUR_SERVICE_INFO.name,
@@ -39,12 +39,12 @@ def mock_chars(mock_read_char_raw):
pytest.param(
AQUA_CONTOUR_SERVICE_INFO,
{
AquaContourWatering.watering_active.uuid: AquaContourWatering.watering_active.encode(
0
AquaContourWatering.watering_active.uuid: (
AquaContourWatering.watering_active.encode(0)
),
AquaContour.operation_mode.uuid: AquaContour.operation_mode.encode(0),
AquaContourPosition.active_position.uuid: AquaContourPosition.active_position.encode(
0
AquaContourPosition.active_position.uuid: (
AquaContourPosition.active_position.encode(0)
),
},
id="aqua_contour",
@@ -86,8 +86,8 @@ async def test_setup(
pytest.param(
AQUA_CONTOUR_SERVICE_INFO,
{
AquaContourBattery.battery_level.uuid: AquaContourBattery.battery_level.encode(
100
AquaContourBattery.battery_level.uuid: (
AquaContourBattery.battery_level.encode(100)
),
FlowStatistics.overall.uuid: FlowStatistics.overall.encode(111),
FlowStatistics.current.uuid: FlowStatistics.overall.encode(222),
@@ -98,8 +98,8 @@ async def test_setup(
1, 1, datetime(2000, 1, 1), AquaContourErrorCode.FLASH_ERROR
)
),
AquaContourWatering.remaining_watering_time.uuid: AquaContourWatering.remaining_watering_time.encode(
100
AquaContourWatering.remaining_watering_time.uuid: (
AquaContourWatering.remaining_watering_time.encode(100)
),
},
id="aqua_contour",
+4 -2
View File
@@ -134,7 +134,7 @@ async def test_image_caching(
freezer: FrozenDateTimeFactory,
fakeimgbytes_png: bytes,
) -> None:
"""Test that the image is cached and not fetched more often than the framerate indicates."""
"""Test image is cached and not fetched more than framerate."""
respx.get("http://example.com").respond(stream=fakeimgbytes_png)
framerate = 5
@@ -334,7 +334,9 @@ async def test_stream_source(
data={},
options={
CONF_STILL_IMAGE_URL: "http://example.com",
CONF_STREAM_SOURCE: 'http://example.com/{{ states.sensor.temp.state + "a" }}',
CONF_STREAM_SOURCE: (
'http://example.com/{{ states.sensor.temp.state + "a" }}'
),
CONF_LIMIT_REFETCH_TO_URL_CHANGE: True,
CONF_FRAMERATE: 2,
CONF_CONTENT_TYPE: "image/png",
@@ -1365,7 +1365,7 @@ async def test_float_tolerance_values(hass: HomeAssistant) -> None:
async def test_float_tolerance_values_2(hass: HomeAssistant) -> None:
"""Test if dehumidifier turns off when oudside of floating point tolerance values."""
"""Test dehumidifier turns off outside of floating point tolerance."""
assert await async_setup_component(
hass,
HUMIDIFIER_DOMAIN,
@@ -163,7 +163,7 @@ async def test_async_handle_source_entity_changes_source_entity_removed(
expected_helper_device_id: str | None,
expected_events: list[str],
) -> None:
"""Test the generic_hygrostat config entry is removed when the source entity is removed."""
"""Test config entry is removed when the source entity is removed."""
source_entity_entry = entity_registry.async_get(source_entity_id)
assert await hass.config_entries.async_setup(
@@ -239,7 +239,7 @@ async def test_async_handle_source_entity_changes_source_entity_removed_shared_d
expected_helper_device_id: str | None,
expected_events: list[str],
) -> None:
"""Test the generic_hygrostat config entry is removed when the source entity is removed."""
"""Test config entry is removed when the source entity is removed."""
source_entity_entry = entity_registry.async_get(source_entity_id)
# Add another config entry to the source device
@@ -1031,7 +1031,7 @@ async def test_heating_cooling_switch_toggles_when_outside_min_cycle_duration(
(False, HVACMode.HEAT, True, 30, 25, HVACMode.OFF, SERVICE_TURN_OFF),
],
)
async def test_hvac_mode_change_toggles_heating_cooling_switch_even_when_within_min_cycle_duration(
async def test_hvac_mode_change_toggles_switch_within_min_cycle_duration(
hass: HomeAssistant,
ac_mode: bool,
initial_hvac_mode: HVACMode,
@@ -167,7 +167,7 @@ async def test_async_handle_source_entity_changes_source_entity_removed(
expected_helper_device_id: str | None,
expected_events: list[str],
) -> None:
"""Test the generic_thermostat config entry is removed when the source entity is removed."""
"""Test config entry is removed when the source entity is removed."""
source_entity_entry = entity_registry.async_get(source_entity_id)
assert await hass.config_entries.async_setup(
@@ -244,7 +244,7 @@ async def test_async_handle_source_entity_changes_source_entity_removed_shared_d
expected_helper_device_id: str | None,
expected_events: list[str],
) -> None:
"""Test the generic_thermostat config entry is removed when the source entity is removed."""
"""Test config entry is removed when the source entity is removed."""
source_entity_entry = entity_registry.async_get(source_entity_id)
# Add another config entry to the source device
@@ -650,7 +650,8 @@ async def test_migration_1_2(hass: HomeAssistant) -> None:
result = await generic_thermostat.async_migrate_entry(hass, config_entry)
assert result is True
# After migration, cooldown should be set to min_cycle_duration and minor version bumped
# After migration, cooldown should be set to min_cycle_duration
# and minor version bumped
assert config_entry.options.get(CONF_DUR_COOLDOWN) == {
"hours": 0,
"minutes": 5,
+1 -1
View File
@@ -32,7 +32,7 @@ async def setup_integration(hass: HomeAssistant, entry: MockConfigEntry) -> None
async def update_callback(
hass: HomeAssistant, mock: AsyncMock, update_type: str, data: dict[str, Any]
) -> None:
"""Invoke the MQTT provider's message callback with the specified update type and data."""
"""Invoke the MQTT provider's message callback."""
for call in mock.listen.call_args_list:
call[0][0](
"topic",
@@ -468,6 +468,6 @@ async def test_zone_undefined(
assert len(service_calls) == 0
assert (
f"Unable to execute automation automation 0: Zone {zone_does_not_exist} not found"
in caplog.text
"Unable to execute automation automation 0:"
f" Zone {zone_does_not_exist} not found" in caplog.text
)
+4 -1
View File
@@ -14,7 +14,10 @@ from homeassistant.components.ghost.const import (
from tests.common import MockConfigEntry
API_URL = "https://test.ghost.io"
API_KEY = "650b7a9f8e8c1234567890ab:1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
API_KEY = (
"650b7a9f8e8c1234567890ab"
":1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
)
SITE_UUID = "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
SITE_DATA = {"title": "Test Ghost", "url": API_URL, "site_uuid": SITE_UUID}
POSTS_DATA = {"published": 42, "drafts": 5, "scheduled": 2}
+1 -1
View File
@@ -43,7 +43,7 @@ async def test_availability_api_error(
mock_gios: MagicMock,
freezer: FrozenDateTimeFactory,
) -> None:
"""Ensure that we mark the entities unavailable correctly when service causes an error."""
"""Ensure entities are marked unavailable when service errors."""
state = hass.states.get("sensor.home_pm2_5")
assert state
assert state.state == "4"
@@ -2,7 +2,8 @@
This test ensures that the go2rtc Docker image SHA pinned in
script/hassfest/docker.py corresponds to a version that is equal to or
greater than the RECOMMENDED_VERSION defined in homeassistant/components/go2rtc/const.py.
greater than the RECOMMENDED_VERSION defined in
homeassistant/components/go2rtc/const.py.
The test pulls the Docker image using the pinned SHA and runs the
`go2rtc --version` command inside the container to extract the version,
@@ -69,7 +70,7 @@ async def _get_version_from_docker_sha() -> str:
reason="This test requires Docker and only runs in CI",
)
async def test_docker_version_matches_recommended() -> None:
"""Test that the go2rtc Docker SHA version matches or exceeds RECOMMENDED_VERSION."""
"""Test go2rtc Docker SHA version meets RECOMMENDED_VERSION."""
# Extract version from the actual Docker container
docker_version_str = await _get_version_from_docker_sha()
+10 -6
View File
@@ -489,8 +489,8 @@ _INVALID_CONFIG = "Invalid config for 'go2rtc': "
ERR_INVALID_URL = _INVALID_CONFIG + "invalid url"
ERR_EXCLUSIVE = _INVALID_CONFIG + DEBUG_UI_URL_MESSAGE
ERR_AUTH_WITHOUT_URL_OR_UI = (
_INVALID_CONFIG
+ "Username and password can only be set when a URL is configured or debug_ui is true"
_INVALID_CONFIG + "Username and password can only be set when a URL is configured"
" or debug_ui is true"
)
ERR_AUTH_INCOMPLETE = (
_INVALID_CONFIG
@@ -861,7 +861,8 @@ async def _test_camera_orientation(
await prefs.async_load()
hass.data[DATA_CAMERA_PREFS] = prefs
# Set the specific orientation for this test by directly setting the dynamic stream settings
# Set the specific orientation for this test by directly setting
# the dynamic stream settings
test_settings = DynamicStreamSettings(orientation=orientation, preload_stream=False)
prefs._dynamic_stream_settings_by_entity_id[camera.entity_id] = test_settings
@@ -1007,7 +1008,10 @@ async def test_stream_orientation_stream_source_starts_ffmpeg(
[HomeAssistant, MockCamera, Orientation, AsyncMock, str], Awaitable[None]
],
) -> None:
"""Test WebRTC provider applies correct orientation filters when a stream source already starts with ffmpeg."""
"""Test WebRTC provider applies correct orientation filters.
Specifically when a stream source already starts with ffmpeg.
"""
camera = init_test_integration
camera.set_stream_source("ffmpeg:rtsp://test.stream")
@@ -1115,7 +1119,7 @@ async def test_unix_socket_not_used_for_custom_server(hass: HomeAssistant) -> No
@pytest.mark.usefixtures("rest_client", "server")
async def test_basic_auth_with_custom_url(hass: HomeAssistant) -> None:
"""Test BasicAuth session is created when username and password are provided with custom URL."""
"""Test BasicAuth session is created with username/password and URL."""
config = {
DOMAIN: {
CONF_URL: "http://localhost:1984/",
@@ -1145,7 +1149,7 @@ async def test_basic_auth_with_custom_url(hass: HomeAssistant) -> None:
@pytest.mark.usefixtures("rest_client")
async def test_basic_auth_with_debug_ui(hass: HomeAssistant, server_dir: Path) -> None:
"""Test BasicAuth session is created when username and password are provided with debug_ui."""
"""Test BasicAuth session created with username/password and debug_ui."""
config = {
DOMAIN: {
CONF_DEBUG_UI: True,
+8 -4
View File
@@ -186,7 +186,8 @@ async def test_server_timeout_on_stop(
"server_stdout",
[
[
"09:00:03.466 INF go2rtc platform=linux/amd64 revision=780f378 version=1.9.5",
"09:00:03.466 INF go2rtc"
" platform=linux/amd64 revision=780f378 version=1.9.5",
"09:00:03.466 INF config path=/tmp/go2rtc.yaml",
]
],
@@ -198,7 +199,7 @@ async def test_server_failed_to_start(
server: Server,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test server, where an exception is raised if the expected log entry was not received until the timeout."""
"""Test server raises exception when expected log not received."""
with (
patch("homeassistant.components.go2rtc.server._SETUP_TIMEOUT", new=0.1),
pytest.raises(HomeAssistantError, match="Go2rtc server didn't start correctly"),
@@ -233,10 +234,13 @@ async def test_server_failed_to_start(
[
"09:00:03.466 TRC [api] register path path=/",
"09:00:03.466 DBG build vcs.time=2024-10-28T19:47:55Z version=go1.23.2",
"09:00:03.466 INF go2rtc platform=linux/amd64 revision=780f378 version=1.9.5",
"09:00:03.466 INF go2rtc"
" platform=linux/amd64 revision=780f378 version=1.9.5",
"09:00:03.467 INF [api] listen addr=127.0.0.1:1984",
"09:00:03.466 WRN warning message",
'09:00:03.466 ERR [api] listen error="listen tcp 127.0.0.1:11984: bind: address already in use"',
"09:00:03.466 ERR [api] listen"
' error="listen tcp 127.0.0.1:11984:'
' bind: address already in use"',
"09:00:03.466 FTL fatal message",
"09:00:03.466 PNC panic message",
"exit with signal: interrupt", # Example of stderr write
+9 -5
View File
@@ -51,7 +51,11 @@ def mock_test_setup(
def get_events_url(entity: str, start: str, end: str) -> str:
"""Create a url to get events during the specified time range."""
return f"/api/calendars/{entity}?start={urllib.parse.quote(start)}&end={urllib.parse.quote(end)}"
return (
f"/api/calendars/{entity}"
f"?start={urllib.parse.quote(start)}"
f"&end={urllib.parse.quote(end)}"
)
def upcoming() -> dict[str, Any]:
@@ -748,7 +752,7 @@ async def test_unique_id_migration(
config_entry,
old_unique_id,
) -> None:
"""Test that old unique id format is migrated to the new format that supports multiple accounts."""
"""Test old unique id format is migrated to new multi-account format."""
config_entry.add_to_hass(hass)
# Create an entity using the old unique id format
entity_registry.async_get_or_create(
@@ -1282,7 +1286,7 @@ async def test_reader_in_progress_event(
async def test_all_day_event_without_duration(
hass: HomeAssistant, mock_events_list_items, component_setup
) -> None:
"""Test that an all day event without a duration is adjusted to have a duration of one day."""
"""Test all day event without duration is adjusted to one day."""
week_from_today = dt_util.now().date() + datetime.timedelta(days=7)
event = {
**TEST_EVENT,
@@ -1377,7 +1381,7 @@ async def test_invalid_rrule_fix(
mock_events_list_items,
component_setup,
) -> None:
"""Test that an invalid RRULE returned from Google Calendar API is handled correctly end to end."""
"""Test invalid RRULE from Google Calendar API is handled."""
week_from_today = dt_util.now().date() + datetime.timedelta(days=7)
end_event = week_from_today + datetime.timedelta(days=1)
event = {
@@ -1467,7 +1471,7 @@ async def test_working_location_entity(
event_type: str,
expected_event_message: str | None,
) -> None:
"""Test that working location events are registered under a disabled by default entity."""
"""Test working location events are disabled by default."""
event = {
**TEST_EVENT,
**upcoming(),
+33 -5
View File
@@ -42,11 +42,29 @@ from tests.common import (
from tests.test_util.aiohttp import AiohttpClientMocker
from tests.typing import ClientSessionGenerator
DUMMY_PRIVATE_KEY = (
"-----BEGIN PRIVATE KEY-----\n"
"MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKYscIlwm7soDs"
"HAz6L6YvUkCvkrX19rS6yeYOmovvhoK5WeYGWUsd8V72zmsyHB7XO94YgJVjvx"
"fzn5K8bLePjFzwoSJjZvhBJ/ZQ05d8VmbvgyWUoPdG9oEa4fZ/lCYrXoaFdTot"
"2xcJvrb/ZuiRl4s4eZpNeFYvVK/Am7UeFPAgMBAAECgYAUetOfzLYUudofvPCaKH"
"u7tKZ5kQPfEa0w6BAPnBF1Mfl1JiDBRDMryFtKs6AOIAVwx00dY/Ex0BCbB3+Cr"
"58H7t4NaPTJxCpmR09pK7o17B7xAdQv8+SynFNud9/5vQ5AEXMOLNwKiU7wpXT6"
"Z7ZIibUBOR7ewsWgsHCDpN1iqQJBAOMODPTPSiQMwRAUHIc6GPleFSJnIz2PAoG"
"3JOG9KFAL6RtIc19lob2ZXdbQdzKtjSkWo+O5W20WDNAl1k32h6MCQQC7W4ZCIY"
"67mPbL6CxXfHjpSGF4Dr9VWJ7ZrKHr6XUoOIcEvsn/pHvWonjMdy93rQMSfOE8B"
"Kd/I1+GHRmNVgplAkAnSo4paxmsZVyfeKt7Jy2dMY+8tVZe17maUuQaAE7Sk00S"
"gJYegwrbMYgQnWCTL39HBfj0dmYA2Zj8CCAuu6O7AkEAryFiYjaUAO9+4iNoL27"
"+ZrFtypeeadyov7gKs0ZKaQpNyzW8A+Zwi7TbTeSqzic/E+z/bOa82q7p/6b714"
"1xsQJBANCAcIwMcVb6KVCHlQbOtKspo5Eh4ZQi8bGl+IcwbQ6JSxeTx915IfAld"
"gbuU047wOB04dYCFB2yLDiUGVXTifU=\n"
"-----END PRIVATE KEY-----\n"
)
DUMMY_CONFIG = GOOGLE_ASSISTANT_SCHEMA(
{
"project_id": "1234",
"service_account": {
"private_key": "-----BEGIN PRIVATE KEY-----\nMIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKYscIlwm7soDsHAz6L6YvUkCvkrX19rS6yeYOmovvhoK5WeYGWUsd8V72zmsyHB7XO94YgJVjvxfzn5K8bLePjFzwoSJjZvhBJ/ZQ05d8VmbvgyWUoPdG9oEa4fZ/lCYrXoaFdTot2xcJvrb/ZuiRl4s4eZpNeFYvVK/Am7UeFPAgMBAAECgYAUetOfzLYUudofvPCaKHu7tKZ5kQPfEa0w6BAPnBF1Mfl1JiDBRDMryFtKs6AOIAVwx00dY/Ex0BCbB3+Cr58H7t4NaPTJxCpmR09pK7o17B7xAdQv8+SynFNud9/5vQ5AEXMOLNwKiU7wpXT6Z7ZIibUBOR7ewsWgsHCDpN1iqQJBAOMODPTPSiQMwRAUHIc6GPleFSJnIz2PAoG3JOG9KFAL6RtIc19lob2ZXdbQdzKtjSkWo+O5W20WDNAl1k32h6MCQQC7W4ZCIY67mPbL6CxXfHjpSGF4Dr9VWJ7ZrKHr6XUoOIcEvsn/pHvWonjMdy93rQMSfOE8BKd/I1+GHRmNVgplAkAnSo4paxmsZVyfeKt7Jy2dMY+8tVZe17maUuQaAE7Sk00SgJYegwrbMYgQnWCTL39HBfj0dmYA2Zj8CCAuu6O7AkEAryFiYjaUAO9+4iNoL27+ZrFtypeeadyov7gKs0ZKaQpNyzW8A+Zwi7TbTeSqzic/E+z/bOa82q7p/6b7141xsQJBANCAcIwMcVb6KVCHlQbOtKspo5Eh4ZQi8bGl+IcwbQ6JSxeTx915IfAldgbuU047wOB04dYCFB2yLDiUGVXTifU=\n-----END PRIVATE KEY-----\n",
"private_key": DUMMY_PRIVATE_KEY,
"client_email": "dummy@dummy.iam.gserviceaccount.com",
},
}
@@ -63,7 +81,17 @@ MOCK_HEADER = {
async def test_get_jwt(hass: HomeAssistant) -> None:
"""Test signing of key."""
jwt = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkdW1teUBkdW1teS5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNjb3BlIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vYXV0aC9ob21lZ3JhcGgiLCJhdWQiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20vby9vYXV0aDIvdG9rZW4iLCJpYXQiOjE1NzEwMTEyMDAsImV4cCI6MTU3MTAxNDgwMH0.akHbMhOflXdIDHVvUVwO0AoJONVOPUdCghN6hAdVz4gxjarrQeGYc_Qn2r84bEvCU7t6EvimKKr0fyupyzBAzfvKULs5mTHO3h2CwSgvOBMv8LnILboJmbO4JcgdnRV7d9G3ktQs7wWSCXJsI5i5jUr1Wfi9zWwxn2ebaAAgrp8"
jwt = (
"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9."
"eyJpc3MiOiJkdW1teUBkdW1teS5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSI"
"sInNjb3BlIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vYXV0aC9ob21"
"lZ3JhcGgiLCJhdWQiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20vby9"
"vYXV0aDIvdG9rZW4iLCJpYXQiOjE1NzEwMTEyMDAsImV4cCI6MTU3MTAxND"
"gwMH0."
"akHbMhOflXdIDHVvUVwO0AoJONVOPUdCghN6hAdVz4gxjarrQeGYc_Qn2r8"
"4bEvCU7t6EvimKKr0fyupyzBAzfvKULs5mTHO3h2CwSgvOBMv8LnILboJmb"
"O4JcgdnRV7d9G3ktQs7wWSCXJsI5i5jUr1Wfi9zWwxn2ebaAAgrp8"
)
res = _get_homegraph_jwt(
datetime(2019, 10, 14, tzinfo=UTC),
DUMMY_CONFIG["service_account"]["client_email"],
@@ -286,7 +314,7 @@ async def test_secure_device_pin_config(hass: HomeAssistant) -> None:
{
"project_id": "1234",
"service_account": {
"private_key": "-----BEGIN PRIVATE KEY-----\nMIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKYscIlwm7soDsHAz6L6YvUkCvkrX19rS6yeYOmovvhoK5WeYGWUsd8V72zmsyHB7XO94YgJVjvxfzn5K8bLePjFzwoSJjZvhBJ/ZQ05d8VmbvgyWUoPdG9oEa4fZ/lCYrXoaFdTot2xcJvrb/ZuiRl4s4eZpNeFYvVK/Am7UeFPAgMBAAECgYAUetOfzLYUudofvPCaKHu7tKZ5kQPfEa0w6BAPnBF1Mfl1JiDBRDMryFtKs6AOIAVwx00dY/Ex0BCbB3+Cr58H7t4NaPTJxCpmR09pK7o17B7xAdQv8+SynFNud9/5vQ5AEXMOLNwKiU7wpXT6Z7ZIibUBOR7ewsWgsHCDpN1iqQJBAOMODPTPSiQMwRAUHIc6GPleFSJnIz2PAoG3JOG9KFAL6RtIc19lob2ZXdbQdzKtjSkWo+O5W20WDNAl1k32h6MCQQC7W4ZCIY67mPbL6CxXfHjpSGF4Dr9VWJ7ZrKHr6XUoOIcEvsn/pHvWonjMdy93rQMSfOE8BKd/I1+GHRmNVgplAkAnSo4paxmsZVyfeKt7Jy2dMY+8tVZe17maUuQaAE7Sk00SgJYegwrbMYgQnWCTL39HBfj0dmYA2Zj8CCAuu6O7AkEAryFiYjaUAO9+4iNoL27+ZrFtypeeadyov7gKs0ZKaQpNyzW8A+Zwi7TbTeSqzic/E+z/bOa82q7p/6b7141xsQJBANCAcIwMcVb6KVCHlQbOtKspo5Eh4ZQi8bGl+IcwbQ6JSxeTx915IfAldgbuU047wOB04dYCFB2yLDiUGVXTifU=\n-----END PRIVATE KEY-----\n",
"private_key": DUMMY_PRIVATE_KEY,
"client_email": "dummy@dummy.iam.gserviceaccount.com",
},
"secure_devices_pin": secure_pin,
@@ -483,8 +511,8 @@ async def test_async_enable_local_sdk(
)
assert resp.status == HTTPStatus.OK
assert (
"Cannot process request for webhook **REDACTED** as no linked agent user is found:"
in caplog.text
"Cannot process request for webhook **REDACTED**"
" as no linked agent user is found:" in caplog.text
)
@@ -545,7 +545,8 @@ async def test_execute(
"params": {"on": True},
},
{
"command": "action.devices.commands.BrightnessAbsolute",
"command": "action.devices.commands"
".BrightnessAbsolute",
"params": {"brightness": 20},
},
],
@@ -706,7 +707,8 @@ async def test_execute_times_out(
"params": {"on": True},
},
{
"command": "action.devices.commands.BrightnessAbsolute",
"command": "action.devices.commands"
".BrightnessAbsolute",
"params": {"brightness": 20},
},
],
@@ -1260,7 +1262,8 @@ async def test_trait_execute_adding_query_data(hass: HomeAssistant) -> None:
"devices": [{"id": "camera.office"}],
"execution": [
{
"command": "action.devices.commands.GetCameraStream",
"command": "action.devices.commands"
".GetCameraStream",
"params": {
"StreamToChromecast": True,
"SupportedStreamProtocols": [
@@ -1342,7 +1345,10 @@ async def test_identify(hass: HomeAssistant) -> None:
"httpPort": 8123,
"httpSSL": False,
"proxyDeviceId": proxy_device_id,
"webhookId": "dde3b9800a905e886cc4d38e226a6e7e3f2a6993d2b9b9f63d13e42ee7de3219",
"webhookId": (
"dde3b9800a905e886cc4d38e226a6e7e"
"3f2a6993d2b9b9f63d13e42ee7de3219"
),
},
}
],
@@ -1421,7 +1427,10 @@ async def test_reachable_devices(hass: HomeAssistant) -> None:
"httpPort": 8123,
"httpSSL": False,
"proxyDeviceId": proxy_device_id,
"webhookId": "dde3b9800a905e886cc4d38e226a6e7e3f2a6993d2b9b9f63d13e42ee7de3219",
"webhookId": (
"dde3b9800a905e886cc4d38e226a6e7e"
"3f2a6993d2b9b9f63d13e42ee7de3219"
),
},
},
{
@@ -1430,7 +1439,10 @@ async def test_reachable_devices(hass: HomeAssistant) -> None:
"httpPort": 8123,
"httpSSL": False,
"proxyDeviceId": proxy_device_id,
"webhookId": "dde3b9800a905e886cc4d38e226a6e7e3f2a6993d2b9b9f63d13e42ee7de3219",
"webhookId": (
"dde3b9800a905e886cc4d38e226a6e7e"
"3f2a6993d2b9b9f63d13e42ee7de3219"
),
},
},
{
@@ -1439,7 +1451,10 @@ async def test_reachable_devices(hass: HomeAssistant) -> None:
"httpPort": 8123,
"httpSSL": False,
"proxyDeviceId": proxy_device_id,
"webhookId": "dde3b9800a905e886cc4d38e226a6e7e3f2a6993d2b9b9f63d13e42ee7de3219",
"webhookId": (
"dde3b9800a905e886cc4d38e226a6e7e"
"3f2a6993d2b9b9f63d13e42ee7de3219"
),
},
},
{"id": proxy_device_id, "customData": {}},
@@ -1346,7 +1346,7 @@ async def test_temperature_setting_climate_onoff(hass: HomeAssistant) -> None:
async def test_temperature_setting_climate_no_modes(hass: HomeAssistant) -> None:
"""Test TemperatureSetting trait support for climate domain not supporting any modes."""
"""Test TemperatureSetting trait for climate with no modes."""
assert helpers.get_google_type(climate.DOMAIN, None) is not None
assert trait.TemperatureSettingTrait.supported(climate.DOMAIN, 0, None, None)
@@ -1794,7 +1794,7 @@ async def test_temperature_control_water_heater_set_temperature(
temp_out: float,
current_init: str,
) -> None:
"""Test TemperatureControl trait support for water heater domain - SetTemperature."""
"""Test TemperatureControl trait for water heater SetTemperature."""
hass.config.units = unit
min_temp = TemperatureConverter.convert(
@@ -2384,7 +2384,7 @@ async def test_fan_speed(hass: HomeAssistant) -> None:
async def test_fan_speed_without_percentage_step(hass: HomeAssistant) -> None:
"""Test FanSpeed trait falls back to percent-only when percentage_step is missing."""
"""Test FanSpeed trait falls back to percent-only without step."""
assert helpers.get_google_type(fan.DOMAIN, None) is not None
assert trait.FanSpeedTrait.supported(
fan.DOMAIN, FanEntityFeature.SET_SPEED, None, None
@@ -58,14 +58,17 @@ def test_best_matching_language_code(hass: HomeAssistant) -> None:
assert best_matching_language_code(hass, "de-DE", "en-AU") == "de-DE"
assert best_matching_language_code(hass, "de-DE") == "de-DE"
# Assist Language is not supported, but agent language has the same "lang" part, and is supported
# Assist Language is not supported, but agent language has the
# same "lang" part, and is supported
assert best_matching_language_code(hass, "en", "en-AU") == "en-AU"
assert best_matching_language_code(hass, "en-XYZ", "en-AU") == "en-AU"
# Assist Language is not supported, but agent language has the same "lang" part, but is not supported
# Assist Language is not supported, but agent language has the
# same "lang" part, but is not supported
assert best_matching_language_code(hass, "en", "en-XYZ") == "en-US"
assert best_matching_language_code(hass, "en-XYZ", "en-ABC") == "en-US"
# Assist Language is not supported, agent is not matching or available, falling back to the default of assist lang
# Assist Language is not supported, agent is not matching or
# available, falling back to the default of assist lang
assert best_matching_language_code(hass, "de", "en-AU") == "de-DE"
assert best_matching_language_code(hass, "de-XYZ", "en-AU") == "de-DE"
assert best_matching_language_code(hass, "de") == "de-DE"
@@ -74,14 +77,17 @@ def test_best_matching_language_code(hass: HomeAssistant) -> None:
# Assist language is not existing at all, agent is supported
assert best_matching_language_code(hass, "abc-XYZ", "en-AU") == "en-AU"
# Assist language is not existing at all, agent is not supported, falling back to the agent default
# Assist language is not existing at all, agent is not supported,
# falling back to the agent default
assert best_matching_language_code(hass, "abc-XYZ", "de-XYZ") == "de-DE"
# Assist language is not existing at all, agent is not existing or available, falling back to system default
# Assist language is not existing at all, agent is not existing or
# available, falling back to system default
assert best_matching_language_code(hass, "abc-XYZ", "def-XYZ") == "es-MX"
assert best_matching_language_code(hass, "abc-XYZ") == "es-MX"
# Assist language is not existing at all, agent is not existing or available, system default is not supported
# Assist language is not existing at all, agent is not existing or
# available, system default is not supported
hass.config.language = "el"
hass.config.country = "GR"
assert best_matching_language_code(hass, "abc-XYZ", "def-XYZ") == "en-US"
@@ -360,7 +360,8 @@ async def test_send_text_command_media_player(
)
assert status == http.HTTPStatus.NOT_FOUND
# Assert that both audio responses can still be served before the 5 minutes expiration
# Assert that both audio responses can still be served before
# the 5 minutes expiration
freezer.tick(timedelta(minutes=4, seconds=59))
async_fire_time_changed(hass)
status, response = await fetch_api_url(hass_client, audio_url1)
+19 -1
View File
@@ -19,7 +19,25 @@ VALID_SERVICE_ACCOUNT_INFO = {
"type": "service_account",
"project_id": "my project id",
"private_key_id": "my private key if",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKYscIlwm7soDsHAz6L6YvUkCvkrX19rS6yeYOmovvhoK5WeYGWUsd8V72zmsyHB7XO94YgJVjvxfzn5K8bLePjFzwoSJjZvhBJ/ZQ05d8VmbvgyWUoPdG9oEa4fZ/lCYrXoaFdTot2xcJvrb/ZuiRl4s4eZpNeFYvVK/Am7UeFPAgMBAAECgYAUetOfzLYUudofvPCaKHu7tKZ5kQPfEa0w6BAPnBF1Mfl1JiDBRDMryFtKs6AOIAVwx00dY/Ex0BCbB3+Cr58H7t4NaPTJxCpmR09pK7o17B7xAdQv8+SynFNud9/5vQ5AEXMOLNwKiU7wpXT6Z7ZIibUBOR7ewsWgsHCDpN1iqQJBAOMODPTPSiQMwRAUHIc6GPleFSJnIz2PAoG3JOG9KFAL6RtIc19lob2ZXdbQdzKtjSkWo+O5W20WDNAl1k32h6MCQQC7W4ZCIY67mPbL6CxXfHjpSGF4Dr9VWJ7ZrKHr6XUoOIcEvsn/pHvWonjMdy93rQMSfOE8BKd/I1+GHRmNVgplAkAnSo4paxmsZVyfeKt7Jy2dMY+8tVZe17maUuQaAE7Sk00SgJYegwrbMYgQnWCTL39HBfj0dmYA2Zj8CCAuu6O7AkEAryFiYjaUAO9+4iNoL27+ZrFtypeeadyov7gKs0ZKaQpNyzW8A+Zwi7TbTeSqzic/E+z/bOa82q7p/6b7141xsQJBANCAcIwMcVb6KVCHlQbOtKspo5Eh4ZQi8bGl+IcwbQ6JSxeTx915IfAldgbuU047wOB04dYCFB2yLDiUGVXTifU=\n-----END PRIVATE KEY-----\n",
"private_key": (
"-----BEGIN PRIVATE KEY-----\n"
"MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKYscIlwm7so"
"DsHAz6L6YvUkCvkrX19rS6yeYOmovvhoK5WeYGWUsd8V72zmsyHB7XO94YgJ"
"Vjvxfzn5K8bLePjFzwoSJjZvhBJ/ZQ05d8VmbvgyWUoPdG9oEa4fZ/lCYrXo"
"aFdTot2xcJvrb/ZuiRl4s4eZpNeFYvVK/Am7UeFPAgMBAAECgYAUetOfzLYU"
"udofvPCaKHu7tKZ5kQPfEa0w6BAPnBF1Mfl1JiDBRDMryFtKs6AOIAVwx00d"
"Y/Ex0BCbB3+Cr58H7t4NaPTJxCpmR09pK7o17B7xAdQv8+SynFNud9/5vQ5A"
"EXMOLNwKiU7wpXT6Z7ZIibUBOR7ewsWgsHCDpN1iqQJBAOMODPTPSiQMwRAU"
"HIc6GPleFSJnIz2PAoG3JOG9KFAL6RtIc19lob2ZXdbQdzKtjSkWo+O5W20W"
"DNAl1k32h6MCQQC7W4ZCIY67mPbL6CxXfHjpSGF4Dr9VWJ7ZrKHr6XUoOIcE"
"vsn/pHvWonjMdy93rQMSfOE8BKd/I1+GHRmNVgplAkAnSo4paxmsZVyfeKt7"
"Jy2dMY+8tVZe17maUuQaAE7Sk00SgJYegwrbMYgQnWCTL39HBfj0dmYA2Zj8"
"CCAuu6O7AkEAryFiYjaUAO9+4iNoL27+ZrFtypeeadyov7gKs0ZKaQpNyzW8"
"A+Zwi7TbTeSqzic/E+z/bOa82q7p/6b7141xsQJBANCAcIwMcVb6KVCHlQbO"
"tKspo5Eh4ZQi8bGl+IcwbQ6JSxeTx915IfAldgbuU047wOB04dYCFB2yLDiUG"
"VXTifU=\n"
"-----END PRIVATE KEY-----\n"
),
"client_email": "my client email",
"client_id": "my client id",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
@@ -201,7 +201,8 @@ async def test_function_call(
"content": {
"parts": [
{
"text": "test function with the provided parameters.",
"text": "test function with the"
" provided parameters.",
"thought_signature": b"_thought_signature_5",
}
],
@@ -308,7 +309,8 @@ async def test_google_search_tool_is_sent(
context = Context()
messages = [
# Messages from the model which contain the google search answer (the usage of the Google Search tool is server side)
# Messages from the model which contain the google search
# answer (the usage of the Google Search tool is server side)
[
GenerateContentResponse(
candidates=[
@@ -686,7 +688,7 @@ async def test_empty_content_in_chat_history(
mock_chat_log: MockChatLog, # noqa: F811
mock_send_message_stream: AsyncMock,
) -> None:
"""Tests that in case of an empty entry in the chat history the google API will receive an injected space sign instead."""
"""Test empty chat history entries get an injected space for the API."""
agent_id = "conversation.google_ai_conversation"
context = Context()
@@ -1,4 +1,4 @@
"""Tests for the diagnostics data provided by the Google Generative AI Conversation integration."""
"""Tests for the Google Generative AI Conversation diagnostics."""
from syrupy.assertion import SnapshotAssertion
@@ -246,13 +246,17 @@ async def test_migration_from_v1(
None,
[
{
"conversation_entity_id": "conversation.google_generative_ai_conversation_2",
"conversation_entity_id": (
"conversation.google_generative_ai_conversation_2"
),
"device_disabled_by": None,
"entity_disabled_by": None,
"device": 1,
},
{
"conversation_entity_id": "conversation.google_generative_ai_conversation",
"conversation_entity_id": (
"conversation.google_generative_ai_conversation"
),
"device_disabled_by": DeviceEntryDisabler.USER,
"entity_disabled_by": RegistryEntryDisabler.DEVICE,
"device": 0,
@@ -267,13 +271,17 @@ async def test_migration_from_v1(
None,
[
{
"conversation_entity_id": "conversation.google_generative_ai_conversation",
"conversation_entity_id": (
"conversation.google_generative_ai_conversation"
),
"device_disabled_by": None,
"entity_disabled_by": None,
"device": 0,
},
{
"conversation_entity_id": "conversation.google_generative_ai_conversation_2",
"conversation_entity_id": (
"conversation.google_generative_ai_conversation_2"
),
"device_disabled_by": DeviceEntryDisabler.USER,
"entity_disabled_by": RegistryEntryDisabler.DEVICE,
"device": 1,
@@ -288,13 +296,17 @@ async def test_migration_from_v1(
ConfigEntryDisabler.USER,
[
{
"conversation_entity_id": "conversation.google_generative_ai_conversation",
"conversation_entity_id": (
"conversation.google_generative_ai_conversation"
),
"device_disabled_by": DeviceEntryDisabler.CONFIG_ENTRY,
"entity_disabled_by": RegistryEntryDisabler.CONFIG_ENTRY,
"device": 0,
},
{
"conversation_entity_id": "conversation.google_generative_ai_conversation_2",
"conversation_entity_id": (
"conversation.google_generative_ai_conversation_2"
),
"device_disabled_by": DeviceEntryDisabler.CONFIG_ENTRY,
"entity_disabled_by": RegistryEntryDisabler.CONFIG_ENTRY,
"device": 1,
+4 -1
View File
@@ -33,7 +33,10 @@ SCOPES = [
]
SENSOR = "sensor.example_gmail_com_vacation_end_date"
TITLE = "example@gmail.com"
TOKEN = "homeassistant.components.google_mail.api.config_entry_oauth2_flow.OAuth2Session.async_ensure_token_valid"
TOKEN = (
"homeassistant.components.google_mail"
".api.config_entry_oauth2_flow.OAuth2Session.async_ensure_token_valid"
)
@pytest.fixture(name="scopes")
+2 -1
View File
@@ -59,7 +59,8 @@ async def test_notify(
blocking=True,
)
assert ex.match(
"Missing 'from' email when setting an alias to show. You have to provide a 'from' email"
"Missing 'from' email when setting an alias to show."
" You have to provide a 'from' email"
)
with patch(BUILD) as mock_client:
@@ -48,7 +48,7 @@ def mock_patch_api(mock_api: Mock) -> Generator[None]:
@pytest.fixture(name="updated_token_entry", autouse=True)
def mock_updated_token_entry() -> dict[str, Any]:
"""Fixture to provide any test specific overrides to token data from the oauth token endpoint."""
"""Fixture to provide test specific overrides to token data."""
return {}
@@ -54,7 +54,7 @@ async def test_no_config_entries(
async def test_no_read_scopes(
hass: HomeAssistant,
) -> None:
"""Test a media source with only write scopes configured so no media source exists."""
"""Test media source with only write scopes has no media source."""
browse = await async_browse_media(hass, f"{URI_SCHEME}{DOMAIN}")
assert browse.domain == DOMAIN
assert browse.identifier is None
@@ -370,7 +370,8 @@ async def test_upload_to_new_album(
"album_id": "album-media-id-2",
}
# Upload an additional item to the same album and assert that no new album is created
# Upload an additional item to the same album and assert that no
# new album is created
mock_api.create_album.reset_mock()
mock_api.create_media_items.reset_mock()
mock_api.create_media_items.return_value = CreateMediaItemsResult(
@@ -408,7 +409,7 @@ async def test_create_album_failed(
config_entry: MockConfigEntry,
mock_api: Mock,
) -> None:
"""Test service call to upload content to a new album but creating the album fails."""
"""Test upload to new album when creating the album fails."""
assert hass.services.has_service(DOMAIN, "upload")
mock_api.create_album.side_effect = GooglePhotosApiError()
+2 -1
View File
@@ -326,7 +326,8 @@ async def test_get_sheet(
assert entries[0].state is ConfigEntryState.LOADED
with patch("homeassistant.components.google_sheets.services.Client") as mock_client:
mock_client.return_value.open_by_key.return_value.worksheet.return_value.get_values.return_value = [
worksheet = mock_client.return_value.open_by_key.return_value.worksheet
worksheet.return_value.get_values.return_value = [
["col1", "col2"],
["a", "b"],
["c", "d"],
@@ -35,7 +35,8 @@ def user_identifier() -> str:
def setup_userinfo(user_identifier: str) -> Generator[Mock]:
"""Set up userinfo."""
with patch("homeassistant.components.google_tasks.config_flow.build") as mock:
mock.return_value.userinfo.return_value.get.return_value.execute.return_value = {
userinfo = mock.return_value.userinfo.return_value.get
userinfo.return_value.execute.return_value = {
"id": user_identifier,
"name": "Test Name",
}
@@ -155,9 +156,13 @@ async def test_api_not_enabled(
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "access_not_configured"
assert (
result["description_placeholders"]["message"]
== "Google Tasks API has not been used in project 0 before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/tasks.googleapis.com/overview?project=0 then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry."
assert result["description_placeholders"]["message"] == (
"Google Tasks API has not been used in project 0 before or it"
" is disabled. Enable it by visiting"
" https://console.developers.google.com/apis/api/"
"tasks.googleapis.com/overview?project=0 then retry."
" If you enabled this API recently, wait a few minutes for"
" the action to propagate to our systems and retry."
)
@@ -105,7 +105,9 @@ async def test_minimum_fields(hass: HomeAssistant) -> None:
(Unauthorized("Invalid API key."), "invalid_auth"),
(
PermissionDenied(
"Requests to this API routes.googleapis.com method google.maps.routing.v2.Routes.ComputeRoutes are blocked."
"Requests to this API routes.googleapis.com method"
" google.maps.routing.v2.Routes.ComputeRoutes"
" are blocked."
),
"permission_denied",
),
@@ -53,7 +53,7 @@ async def test_availability(
mock_google_weather_api: AsyncMock,
freezer: FrozenDateTimeFactory,
) -> None:
"""Ensure that we mark the entities unavailable correctly when service is offline."""
"""Ensure entities are marked unavailable when service is offline."""
entity_id = "sensor.home_temperature"
await hass.config_entries.async_setup(mock_config_entry.entry_id)
@@ -163,7 +163,8 @@ async def test_state_update(
assert state
assert state.state == "13.7"
mock_google_weather_api.async_get_current_conditions.return_value.temperature.degrees = 15.0
current = mock_google_weather_api.async_get_current_conditions
current.return_value.temperature.degrees = 15.0
freezer.tick(timedelta(minutes=15))
async_fire_time_changed(hass)
@@ -50,7 +50,7 @@ async def test_availability(
mock_google_weather_api: AsyncMock,
freezer: FrozenDateTimeFactory,
) -> None:
"""Ensure that we mark the entities unavailable correctly when service is offline."""
"""Ensure entities are marked unavailable when service is offline."""
entity_id = "weather.home"
await hass.config_entries.async_setup(mock_config_entry.entry_id)
@@ -131,10 +131,9 @@ async def test_condition(
expected_ha_condition: str,
) -> None:
"""Test condition mapping."""
mock_google_weather_api.async_get_current_conditions.return_value.weather_condition.type = api_condition
mock_google_weather_api.async_get_current_conditions.return_value.is_daytime = (
is_daytime
)
current = mock_google_weather_api.async_get_current_conditions
current.return_value.weather_condition.type = api_condition
current.return_value.is_daytime = is_daytime
await hass.config_entries.async_setup(mock_config_entry.entry_id)
+11 -3
View File
@@ -103,7 +103,10 @@ GV5125_BUTTON_1_SERVICE_INFO = BluetoothServiceInfo(
rssi=-36,
manufacturer_data={
60552: b"\x01\n.\xaf\xd9085Sg\x01\x01",
61320: b".\xaf\x00\x00\xfb\x0e\xc9h\xd7\x05l\xaf*\xf3\x1b\xe8w\xf1\xe1\xe8\xe3\xa7\xf8\xc6",
61320: (
b".\xaf\x00\x00\xfb\x0e\xc9h\xd7\x05l\xaf*\xf3\x1b"
b"\xe8w\xf1\xe1\xe8\xe3\xa7\xf8\xc6"
),
},
service_data={},
service_uuids=[],
@@ -116,7 +119,9 @@ GV5121_MOTION_SERVICE_INFO = BluetoothServiceInfo(
address="C1:37:37:32:0F:45",
rssi=-36,
manufacturer_data={
61320: b"Y\x94\x00\x00\xf0\xb9\x197\xaeP\xb67,\x86j\xc2\xf3\xd0a\xe7\x17\xc0,\xef"
61320: (
b"Y\x94\x00\x00\xf0\xb9\x197\xaeP\xb67,\x86j\xc2\xf3\xd0a\xe7\x17\xc0,\xef"
)
},
service_data={},
service_uuids=[],
@@ -129,7 +134,10 @@ GV5121_MOTION_SERVICE_INFO_2 = BluetoothServiceInfo(
address="C1:37:37:32:0F:45",
rssi=-36,
manufacturer_data={
61320: b"Y\x94\x00\x06\xa3f6e\xc8\xe6\xfdv\x04\xaf\xe7k\xbf\xab\xeb\xbf\xb3\xa3\xd5\x19"
61320: (
b"Y\x94\x00\x06\xa3f6e\xc8\xe6\xfdv\x04\xaf\xe7k"
b"\xbf\xab\xeb\xbf\xb3\xa3\xd5\x19"
)
},
service_data={},
service_uuids=[],
+1 -1
View File
@@ -502,7 +502,7 @@ async def test_send_target_temperature_with_hvac_mode(
async def test_send_target_temperature_device_timeout(
hass: HomeAssistant, discovery, device, units: UnitSystem, temperature
) -> None:
"""Test for sending target temperature command to the device with a device timeout."""
"""Test sending target temperature command with device timeout."""
hass.config.units = units
if units.temperature_unit == UnitOfTemperature.FAHRENHEIT:
device().temperature_units = 1
@@ -64,7 +64,8 @@ def mock_api() -> Generator[MagicMock]:
# Make get_electricity_prices async since coordinator uses it
mock_api_instance.get_electricity_prices = AsyncMock(return_value=all_prices)
# Mock the calculation methods to return actual values in Cent/kWh (not coroutines)
# Mock the calculation methods to return actual values in
# Cent/kWh (not coroutines)
# Highest price today: 20 + (23 * 1) = 43 Cent/kWh at hour 23
mock_api_instance.get_highest_price_today.return_value = 43.0
mock_api_instance.get_highest_price_today_with_hour.return_value = (43.0, 23)
+6 -6
View File
@@ -31,7 +31,7 @@ SINGLE_MONITOR_SERIAL_NUMBER = 110011
def make_single_monitor_config_with_sensors(sensors: dict[str, Any]) -> dict[str, Any]:
"""Wrap the given sensor config in the boilerplate for a single monitor with serial number SINGLE_MONITOR_SERIAL_NUMBER."""
"""Wrap sensor config in boilerplate for SINGLE_MONITOR_SERIAL_NUMBER."""
return {
DOMAIN: {
CONF_PORT: 7513,
@@ -160,7 +160,7 @@ MULTI_MONITOR_CONFIG = {
async def setup_greeneye_monitor_component_with_config(
hass: HomeAssistant, config: ConfigType
) -> bool:
"""Set up the greeneye_monitor component with the given config. Return True if successful, False otherwise."""
"""Set up the greeneye_monitor component with the given config."""
result = await async_setup_component(
hass,
DOMAIN,
@@ -172,21 +172,21 @@ async def setup_greeneye_monitor_component_with_config(
def mock_with_listeners() -> MagicMock:
"""Create a MagicMock with methods that follow the same pattern for working with listeners in the greeneye_monitor API."""
"""Create a MagicMock with greeneye_monitor API listener methods."""
mock = MagicMock()
add_listeners(mock)
return mock
def async_mock_with_listeners() -> AsyncMock:
"""Create an AsyncMock with methods that follow the same pattern for working with listeners in the greeneye_monitor API."""
"""Create an AsyncMock with greeneye_monitor API listener methods."""
mock = AsyncMock()
add_listeners(mock)
return mock
def add_listeners(mock: MagicMock | AsyncMock) -> None:
"""Add add_listener and remove_listener methods to the given mock that behave like their counterparts on objects from the greeneye_monitor API, plus a notify_all_listeners method that calls all registered listeners."""
"""Add listener methods to the mock matching the greeneye_monitor API."""
mock.listeners = []
mock.add_listener = mock.listeners.append
mock.remove_listener = mock.listeners.remove
@@ -243,7 +243,7 @@ def mock_monitor(serial_number: int) -> MagicMock:
async def connect_monitor(
hass: HomeAssistant, monitors: AsyncMock, serial_number: int
) -> MagicMock:
"""Simulate a monitor connecting to Home Assistant. Returns the mock monitor API object."""
"""Simulate a monitor connecting to Home Assistant."""
monitor = mock_monitor(serial_number)
monitors.add_monitor(monitor)
await hass.async_block_till_done()
@@ -21,7 +21,7 @@ def assert_sensor_state(
expected_state: str,
attributes: dict[str, Any] | None = None,
) -> None:
"""Assert that the given entity has the expected state and at least the provided attributes."""
"""Assert entity has expected state and provided attributes."""
state = hass.states.get(entity_id)
assert state
actual_state = state.state
@@ -99,14 +99,14 @@ def assert_sensor_registered(
@pytest.fixture
def monitors() -> Generator[AsyncMock]:
"""Provide a mock greeneye.Monitors object that has listeners and can add new monitors."""
"""Provide a mock greeneye.Monitors object with listeners."""
with patch("greeneye.Monitors", autospec=True) as mock_monitors:
mock = mock_monitors.return_value
add_listeners(mock)
mock.monitors = {}
def add_monitor(monitor: MagicMock) -> None:
"""Add the given mock monitor as a monitor with the given serial number, notifying any listeners on the Monitors object."""
"""Add mock monitor and notify listeners."""
serial_number = monitor.serial_number
mock.monitors[serial_number] = monitor
mock.notify_all_listeners(monitor)
@@ -156,7 +156,7 @@ async def test_multi_monitor_config(hass: HomeAssistant, monitors: AsyncMock) ->
async def test_setup_and_shutdown(hass: HomeAssistant, monitors: AsyncMock) -> None:
"""Test that the component can set up and shut down cleanly, closing the underlying server on shutdown."""
"""Test the component can set up and shut down cleanly."""
monitors.start_server = AsyncMock(return_value=None)
monitors.close = AsyncMock(return_value=None)
assert await setup_greeneye_monitor_component_with_config(
@@ -27,7 +27,8 @@ async def test_sensor_does_not_exist_before_monitor_connected(
hass: HomeAssistant, entity_registry: er.EntityRegistry, monitors: AsyncMock
) -> None:
"""Test that a sensor does not exist before its monitor is connected."""
# The sensor base class handles connecting the monitor, so we test this with a single voltage sensor for ease
# The sensor base class handles connecting the monitor, so we test
# this with a single voltage sensor for ease
await setup_greeneye_monitor_component_with_config(
hass, SINGLE_MONITOR_CONFIG_VOLTAGE_SENSORS
)
@@ -39,7 +40,8 @@ async def test_sensors_created_when_monitor_connected(
hass: HomeAssistant, monitors: AsyncMock
) -> None:
"""Test that sensors get created when the monitor first connects."""
# The sensor base class handles updating the state on connection, so we test this with a single voltage sensor for ease
# The sensor base class handles updating the state on connection,
# so we test this with a single voltage sensor for ease
await setup_greeneye_monitor_component_with_config(
hass, SINGLE_MONITOR_CONFIG_VOLTAGE_SENSORS
)
@@ -53,8 +55,9 @@ async def test_sensors_created_when_monitor_connected(
async def test_sensors_created_during_setup_if_monitor_already_connected(
hass: HomeAssistant, monitors: AsyncMock
) -> None:
"""Test that sensors get created during setup if the monitor happens to connect really quickly."""
# The sensor base class handles updating the state on connection, so we test this with a single voltage sensor for ease
"""Test sensors get created during setup if monitor connects fast."""
# The sensor base class handles updating the state on connection,
# so we test this with a single voltage sensor for ease
await connect_monitor(hass, monitors, SINGLE_MONITOR_SERIAL_NUMBER)
await setup_greeneye_monitor_component_with_config(
hass, SINGLE_MONITOR_CONFIG_VOLTAGE_SENSORS
@@ -67,8 +70,9 @@ async def test_sensors_created_during_setup_if_monitor_already_connected(
async def test_disable_sensor_after_monitor_connected(
hass: HomeAssistant, monitors: AsyncMock
) -> None:
"""Test that a sensor disabled after its monitor connected stops listening for sensor changes."""
# The sensor base class handles connecting the monitor, so we test this with a single voltage sensor for ease
"""Test disabled sensor stops listening for changes."""
# The sensor base class handles connecting the monitor, so we test
# this with a single voltage sensor for ease
await setup_greeneye_monitor_component_with_config(
hass, SINGLE_MONITOR_CONFIG_VOLTAGE_SENSORS
)
@@ -82,8 +86,9 @@ async def test_disable_sensor_after_monitor_connected(
async def test_updates_state_when_sensor_pushes(
hass: HomeAssistant, monitors: AsyncMock
) -> None:
"""Test that a sensor entity updates its state when the underlying sensor pushes an update."""
# The sensor base class handles triggering state updates, so we test this with a single voltage sensor for ease
"""Test sensor entity updates state when underlying sensor pushes."""
# The sensor base class handles triggering state updates, so we
# test this with a single voltage sensor for ease
await setup_greeneye_monitor_component_with_config(
hass, SINGLE_MONITOR_CONFIG_VOLTAGE_SENSORS
)
@@ -98,7 +103,7 @@ async def test_updates_state_when_sensor_pushes(
async def test_power_sensor_initially_unknown(
hass: HomeAssistant, monitors: AsyncMock
) -> None:
"""Test that the power sensor can handle its initial state being unknown (since the GEM API needs at least two packets to arrive before it can compute watts)."""
"""Test power sensor handles initial unknown state."""
await setup_greeneye_monitor_component_with_config(
hass, SINGLE_MONITOR_CONFIG_POWER_SENSORS
)
@@ -114,7 +119,7 @@ async def test_power_sensor_initially_unknown(
async def test_power_sensor(hass: HomeAssistant, monitors: AsyncMock) -> None:
"""Test that a power sensor reports its values correctly, including handling net metering."""
"""Test power sensor reports values including net metering."""
await setup_greeneye_monitor_component_with_config(
hass, SINGLE_MONITOR_CONFIG_POWER_SENSORS
)
@@ -132,7 +137,7 @@ async def test_power_sensor(hass: HomeAssistant, monitors: AsyncMock) -> None:
async def test_pulse_counter_initially_unknown(
hass: HomeAssistant, monitors: AsyncMock
) -> None:
"""Test that the pulse counter sensor can handle its initial state being unknown (since the GEM API needs at least two packets to arrive before it can compute pulses per time)."""
"""Test pulse counter handles initial unknown state."""
await setup_greeneye_monitor_component_with_config(
hass, SINGLE_MONITOR_CONFIG_PULSE_COUNTERS
)
@@ -153,7 +158,7 @@ async def test_pulse_counter_initially_unknown(
async def test_pulse_counter(hass: HomeAssistant, monitors: AsyncMock) -> None:
"""Test that a pulse counter sensor reports its values properly, including calculating different units."""
"""Test pulse counter sensor reports values with unit conversion."""
await setup_greeneye_monitor_component_with_config(
hass, SINGLE_MONITOR_CONFIG_PULSE_COUNTERS
)
@@ -168,7 +173,7 @@ async def test_pulse_counter(hass: HomeAssistant, monitors: AsyncMock) -> None:
async def test_temperature_sensor(hass: HomeAssistant, monitors: AsyncMock) -> None:
"""Test that a temperature sensor reports its values properly, including proper handling of when its native unit is different from that configured in hass."""
"""Test temperature sensor handles native unit conversion."""
await setup_greeneye_monitor_component_with_config(
hass, SINGLE_MONITOR_CONFIG_TEMPERATURE_SENSORS
)
+4 -2
View File
@@ -56,8 +56,10 @@ async def test_state_reporting_all(hass: HomeAssistant) -> None:
"""Test the state reporting in 'all' mode.
The group state is unavailable if all group members are unavailable.
Otherwise, the group state is unknown if at least one group member is unknown or unavailable.
Otherwise, the group state is off if at least one group member is off.
Otherwise, the group state is unknown if at least one group member
is unknown or unavailable.
Otherwise, the group state is off if at least one group member is
off.
Otherwise, the group state is on.
"""
await async_setup_component(
+2 -1
View File
@@ -899,7 +899,8 @@ async def test_assumed_state(hass: HomeAssistant) -> None:
state = hass.states.get(COVER_GROUP)
assert state.attributes.get(ATTR_ASSUMED_STATE) is True
# All members without assumed_state -> group doesn't have assumed_state in attributes
# All members without assumed_state -> group doesn't have
# assumed_state in attributes
hass.states.async_set(DEMO_TILT, CoverState.CLOSED, {})
await hass.async_block_till_done()
+2 -1
View File
@@ -625,7 +625,8 @@ async def test_assumed_state(hass: HomeAssistant) -> None:
state = hass.states.get(FAN_GROUP)
assert state.attributes.get(ATTR_ASSUMED_STATE) is True
# All members without assumed_state -> group doesn't have assumed_state in attributes
# All members without assumed_state -> group doesn't have
# assumed_state in attributes
hass.states.async_set(LIVING_ROOM_FAN_ENTITY_ID, STATE_ON, {})
await hass.async_block_till_done()
+25 -5
View File
@@ -1213,7 +1213,9 @@ async def test_group_persons_and_device_trackers(hass: HomeAssistant) -> None:
{
"group": {
"group_zero": {
"entities": "device_tracker.one, person.one, person.two, person.three"
"entities": (
"device_tracker.one, person.one, person.two, person.three"
)
},
}
},
@@ -1238,7 +1240,12 @@ async def test_group_mixed_domains_on(hass: HomeAssistant) -> None:
"group": {
"group_zero": {
"all": "true",
"entities": "lock.alexander_garage_exit_door, binary_sensor.alexander_garage_side_door_open, cover.small_garage_door",
"entities": (
"lock.alexander_garage_exit_door,"
" binary_sensor"
".alexander_garage_side_door_open,"
" cover.small_garage_door"
),
},
}
},
@@ -1263,7 +1270,12 @@ async def test_group_mixed_domains_off(hass: HomeAssistant) -> None:
"group": {
"group_zero": {
"all": "true",
"entities": "lock.alexander_garage_exit_door, binary_sensor.alexander_garage_side_door_open, cover.small_garage_door",
"entities": (
"lock.alexander_garage_exit_door,"
" binary_sensor"
".alexander_garage_side_door_open,"
" cover.small_garage_door"
),
},
}
},
@@ -1400,7 +1412,11 @@ async def test_group_alarm(hass: HomeAssistant) -> None:
{
"group": {
"group_zero": {
"entities": "alarm_control_panel.one, alarm_control_panel.two, alarm_control_panel.three"
"entities": (
"alarm_control_panel.one,"
" alarm_control_panel.two,"
" alarm_control_panel.three"
)
},
}
},
@@ -1425,7 +1441,11 @@ async def test_group_alarm_disarmed(hass: HomeAssistant) -> None:
{
"group": {
"group_zero": {
"entities": "alarm_control_panel.one, alarm_control_panel.two, alarm_control_panel.three"
"entities": (
"alarm_control_panel.one,"
" alarm_control_panel.two,"
" alarm_control_panel.three"
)
},
}
},
+8 -4
View File
@@ -180,9 +180,12 @@ async def test_state_reporting_any(hass: HomeAssistant) -> None:
async def test_state_reporting_all(hass: HomeAssistant) -> None:
"""Test the state reporting in 'all' mode.
The group state is unavailable if all group members are unavailable.
Otherwise, the group state is unknown if at least one group member is unknown or unavailable.
Otherwise, the group state is off if at least one group member is off.
The group state is unavailable if all group members are
unavailable.
Otherwise, the group state is unknown if at least one group member
is unknown or unavailable.
Otherwise, the group state is off if at least one group member is
off.
Otherwise, the group state is on.
"""
await async_setup_component(
@@ -1738,7 +1741,8 @@ async def test_assumed_state(hass: HomeAssistant) -> None:
state = hass.states.get("light.light_group")
assert state.attributes.get(ATTR_ASSUMED_STATE) is True
# All members without assumed_state -> group doesn't have assumed_state in attributes
# All members without assumed_state -> group doesn't have
# assumed_state in attributes
hass.states.async_set("light.living_room", STATE_OFF, {})
await hass.async_block_till_done()
+12 -6
View File
@@ -57,12 +57,18 @@ async def test_default_state(
async def test_state_reporting(hass: HomeAssistant) -> None:
"""Test the state reporting.
The group state is unavailable if all group members are unavailable.
Otherwise, the group state is unknown if at least one group member is unknown or unavailable.
Otherwise, the group state is jammed if at least one group member is jammed.
Otherwise, the group state is locking if at least one group member is locking.
Otherwise, the group state is unlocking if at least one group member is unlocking.
Otherwise, the group state is unlocked if at least one group member is unlocked.
The group state is unavailable if all group members are
unavailable.
Otherwise, the group state is unknown if at least one group member
is unknown or unavailable.
Otherwise, the group state is jammed if at least one group member
is jammed.
Otherwise, the group state is locking if at least one group member
is locking.
Otherwise, the group state is unlocking if at least one group
member is unlocking.
Otherwise, the group state is unlocked if at least one group
member is unlocked.
Otherwise, the group state is locked.
"""
await async_setup_component(
+2 -1
View File
@@ -105,7 +105,8 @@ async def test_state_reporting(hass: HomeAssistant) -> None:
Otherwise, the group state is idle if all group members are idle.
Otherwise, the group state is paused if all group members are paused.
Otherwise, the group state is playing if all group members are playing.
Otherwise, the group state is on if at least one group member is not off, unavailable or unknown.
Otherwise, the group state is on if at least one group member is
not off, unavailable or unknown.
Otherwise, the group state is off.
"""
await async_setup_component(
+5 -5
View File
@@ -594,8 +594,8 @@ async def test_sensor_with_uoms_but_no_device_class(
assert state.state == STATE_UNKNOWN
assert (
"Unable to use state. Only entities with correct unit of measurement is supported"
in caplog.text
"Unable to use state. Only entities with correct unit"
" of measurement is supported" in caplog.text
)
hass.states.async_set(
@@ -618,7 +618,7 @@ async def test_sensor_with_uoms_but_no_device_class(
async def test_sensor_calculated_properties_not_same(
hass: HomeAssistant, issue_registry: ir.IssueRegistry
) -> None:
"""Test the sensor calculating device_class, state_class and unit of measurement not same."""
"""Test sensor calculating properties when not all the same."""
config = {
SENSOR_DOMAIN: {
"platform": DOMAIN,
@@ -754,7 +754,7 @@ async def test_sensor_calculated_properties_not_convertible_device_class(
hass: HomeAssistant,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test the sensor calculating device_class, state_class and unit of measurement when device class not convertible."""
"""Test sensor with non-convertible device class."""
config = {
SENSOR_DOMAIN: {
"platform": DOMAIN,
@@ -924,7 +924,7 @@ async def test_first_available_sensor(hass: HomeAssistant) -> None:
async def test_sensors_attributes_added_when_entity_info_available(
hass: HomeAssistant,
) -> None:
"""Test the sensor calculate attributes once all entities attributes are available."""
"""Test sensor calculates attributes once all entities are available."""
config = {
SENSOR_DOMAIN: {
"platform": DOMAIN,
+8 -4
View File
@@ -151,9 +151,12 @@ async def test_state_reporting(hass: HomeAssistant) -> None:
async def test_state_reporting_all(hass: HomeAssistant) -> None:
"""Test the state reporting in 'all' mode.
The group state is unavailable if all group members are unavailable.
Otherwise, the group state is unknown if at least one group member is unknown or unavailable.
Otherwise, the group state is off if at least one group member is off.
The group state is unavailable if all group members are
unavailable.
Otherwise, the group state is unknown if at least one group member
is unknown or unavailable.
Otherwise, the group state is off if at least one group member is
off.
Otherwise, the group state is on.
"""
await async_setup_component(
@@ -493,7 +496,8 @@ async def test_assumed_state(hass: HomeAssistant) -> None:
state = hass.states.get("switch.media_group")
assert state.attributes.get(ATTR_ASSUMED_STATE) is True
# All members without assumed_state -> group doesn't have assumed_state in attributes
# All members without assumed_state -> group doesn't have
# assumed_state in attributes
hass.states.async_set("switch.tv", STATE_ON, {})
await hass.async_block_till_done()
+2 -1
View File
@@ -631,7 +631,8 @@ async def test_assumed_state(hass: HomeAssistant) -> None:
state = hass.states.get(VALVE_GROUP)
assert state.attributes.get(ATTR_ASSUMED_STATE) is True
# All members without assumed_state -> group doesn't have assumed_state in attributes
# All members without assumed_state -> group doesn't have
# assumed_state in attributes
hass.states.async_set(DEMO_VALVE2, ValveState.CLOSED, {})
await hass.async_block_till_done()
+10 -7
View File
@@ -33,7 +33,8 @@ def mock_growatt_v1_api():
Methods mocked for MIN device coordinator refresh:
- min_detail: Provides device state (e.g., acChargeEnable, chargePowerCommand)
- min_settings: Provides settings (e.g. TOU periods)
- min_energy: Provides energy data (empty for switch/number tests, sensors need real data)
- min_energy: Provides energy data (empty for switch/number tests,
sensors need real data)
Methods mocked for switch and number operations:
- min_write_parameter: Called by switch/number entities to change settings
@@ -74,8 +75,8 @@ def mock_growatt_v1_api():
"chargePowerCommand": 50, # 50% charge power - read by number entity
"wchargeSOCLowLimit": 10, # 10% charge stop SOC - read by number entity
"disChargePowerCommand": 80, # 80% discharge power - read by number entity
"wdisChargeSOCLowLimit": 20, # 20% discharge stop SOC (off-grid) - read by number entity
"onGridDischargeStopSOC": 15, # 15% on-grid discharge stop SOC - read by number entity
"wdisChargeSOCLowLimit": 20, # 20% discharge stop SOC (off-grid)
"onGridDischargeStopSOC": 15, # 15% on-grid discharge stop SOC
}
# Called by MIN device coordinator during refresh
@@ -147,7 +148,8 @@ def mock_growatt_v1_api():
mock_v1_api.min_write_parameter.return_value = None
# Called by MIN time segment management services
# Note: Don't use autospec for this method as it needs to accept variable arguments
# Note: Don't use autospec for this method as it needs to
# accept variable arguments
mock_v1_api.min_write_time_segment = Mock(
return_value={
"error_code": 0,
@@ -425,9 +427,10 @@ async def init_integration(
) -> MockConfigEntry:
"""Set up the Growatt Server integration for testing (V1 API).
This combines mock_config_entry and mock_growatt_v1_api to provide a fully
initialized integration ready for testing. Use @pytest.mark.usefixtures("init_integration")
to automatically set up the integration before your test runs.
This combines mock_config_entry and mock_growatt_v1_api to provide a
fully initialized integration ready for testing.
Use @pytest.mark.usefixtures("init_integration") to automatically
set up the integration before your test runs.
For Classic API tests, manually set up using mock_config_entry_classic and
mock_growatt_classic_api instead.
@@ -770,7 +770,7 @@ async def test_reauth_password_success(
user_input: dict[str, str],
expected_region: str,
) -> None:
"""Test successful reauthentication with password auth for default and non-default regions."""
"""Test successful reauthentication with password auth."""
entry = MockConfigEntry(
domain=DOMAIN,
data={
@@ -946,7 +946,7 @@ async def test_reauth_token_non_auth_api_error(
mock_growatt_v1_api: MagicMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test reauth token with non-auth V1 API error (e.g. rate limit) shows cannot_connect."""
"""Test reauth token with non-auth V1 API error."""
mock_config_entry.add_to_hass(hass)
result = await mock_config_entry.start_reauth_flow(hass)
@@ -1078,7 +1078,7 @@ async def test_reauth_token_exception(
mock_growatt_v1_api: MagicMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test reauth token flow with unexpected exception from plant_list, then recovery."""
"""Test reauth token flow with unexpected exception, then recovery."""
mock_config_entry.add_to_hass(hass)
result = await mock_config_entry.start_reauth_flow(hass)
@@ -1159,7 +1159,7 @@ async def test_reconfigure_password_success(
user_input: dict[str, str],
expected_region: str,
) -> None:
"""Test successful reconfiguration with password auth for default and non-default regions."""
"""Test successful reconfiguration with password auth."""
entry = MockConfigEntry(
domain=DOMAIN,
data={
@@ -1323,7 +1323,7 @@ async def test_reconfigure_token_error_then_recovery(
async def test_reconfigure_unknown_auth_type(hass: HomeAssistant) -> None:
"""Test reconfigure aborts immediately when the config entry has an unknown auth type."""
"""Test reconfigure aborts with unknown auth type."""
entry = MockConfigEntry(
domain=DOMAIN,
data={
+2 -2
View File
@@ -178,7 +178,7 @@ async def test_setup_auth_failed_on_permission_denied(
mock_growatt_v1_api,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test that error 10011 (no privilege) from device_list triggers reauth during setup."""
"""Test error 10011 from device_list triggers reauth during setup."""
error = growattServer.GrowattV1ApiError(
message="Permission denied",
error_code=growattServer.GrowattV1ApiErrorCode.NO_PRIVILEGE,
@@ -237,7 +237,7 @@ async def test_classic_api_coordinator_auth_failed_triggers_reauth(
mock_config_entry_classic: MockConfigEntry,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test that invalid classic API credentials during coordinator update trigger reauth."""
"""Test invalid classic API credentials trigger reauth on update."""
mock_growatt_classic_api.device_list.return_value = [
{"deviceSn": "TLX123456", "deviceType": "tlx"}
]
@@ -185,7 +185,7 @@ async def test_step_dhcp_already_in_progress(hass: HomeAssistant) -> None:
async def test_step_dhcp_already_setup_match_mac(hass: HomeAssistant) -> None:
"""Test we abort if the device is already setup with matching unique id and discovered via DHCP."""
"""Test we abort if already setup with matching unique id via DHCP."""
entry = MockConfigEntry(
domain=DOMAIN, data={CONF_IP_ADDRESS: "1.2.3.4"}, unique_id="guardian_ABCD"
)
@@ -205,7 +205,7 @@ async def test_step_dhcp_already_setup_match_mac(hass: HomeAssistant) -> None:
async def test_step_dhcp_already_setup_match_ip(hass: HomeAssistant) -> None:
"""Test we abort if the device is already setup with matching ip and discovered via DHCP."""
"""Test we abort if already setup with matching ip via DHCP."""
entry = MockConfigEntry(
domain=DOMAIN,
data={CONF_IP_ADDRESS: "192.168.1.100"},