|
6 | 6 | from freezegun import freeze_time |
7 | 7 | import pytest |
8 | 8 |
|
| 9 | +from homeassistant.auth.models import User |
9 | 10 | from homeassistant.components import alarm_control_panel |
10 | 11 | from homeassistant.components.alarm_control_panel import ( |
| 12 | + DOMAIN as ALARM_DOMAIN, |
11 | 13 | AlarmControlPanelEntityFeature, |
12 | 14 | AlarmControlPanelState, |
13 | 15 | ) |
|
25 | 27 | SERVICE_ALARM_ARM_NIGHT, |
26 | 28 | SERVICE_ALARM_ARM_VACATION, |
27 | 29 | ) |
28 | | -from homeassistant.core import CoreState, HomeAssistant, State |
| 30 | +from homeassistant.core import Context, CoreState, HomeAssistant, State, callback |
29 | 31 | from homeassistant.exceptions import ServiceValidationError |
30 | 32 | from homeassistant.setup import async_setup_component |
31 | 33 | from homeassistant.util import dt as dt_util |
@@ -1123,6 +1125,80 @@ async def test_disarm_during_trigger_with_invalid_code(hass: HomeAssistant) -> N |
1123 | 1125 | assert state.state == AlarmControlPanelState.TRIGGERED |
1124 | 1126 |
|
1125 | 1127 |
|
| 1128 | +async def test_bad_code_attempt_event_fired(hass: HomeAssistant) -> None: |
| 1129 | + """Test that manual_alarm_bad_code_attempt event is fired on bad code.""" |
| 1130 | + |
| 1131 | + entity_id = "alarm_control_panel.test_alarm" |
| 1132 | + config = { |
| 1133 | + ALARM_DOMAIN: { |
| 1134 | + "platform": "manual", |
| 1135 | + "name": "Test Alarm", |
| 1136 | + "code": "1234", |
| 1137 | + "delay_time": 0, |
| 1138 | + "arming_time": 0, |
| 1139 | + "trigger_time": 0, |
| 1140 | + } |
| 1141 | + } |
| 1142 | + assert await async_setup_component(hass, ALARM_DOMAIN, config) |
| 1143 | + await hass.async_block_till_done() |
| 1144 | + |
| 1145 | + alarm_entity = hass.states.get(entity_id) |
| 1146 | + assert alarm_entity is not None |
| 1147 | + |
| 1148 | + await hass.services.async_call( |
| 1149 | + ALARM_DOMAIN, |
| 1150 | + "alarm_arm_away", |
| 1151 | + {"entity_id": entity_id, "code": "1234"}, |
| 1152 | + blocking=True, |
| 1153 | + ) |
| 1154 | + await hass.async_block_till_done() |
| 1155 | + assert hass.states.get(entity_id).state == AlarmControlPanelState.ARMED_AWAY |
| 1156 | + |
| 1157 | + bad_code = "0000" |
| 1158 | + |
| 1159 | + mock_user_id = "test_user_id_123" |
| 1160 | + test_context = Context(user_id=mock_user_id) |
| 1161 | + |
| 1162 | + events = [] |
| 1163 | + |
| 1164 | + @callback |
| 1165 | + def event_listener(event): |
| 1166 | + events.append(event.data) |
| 1167 | + |
| 1168 | + hass.bus.async_listen("manual_alarm_bad_code_attempt", event_listener) |
| 1169 | + |
| 1170 | + await hass.services.async_call( |
| 1171 | + ALARM_DOMAIN, |
| 1172 | + "alarm_disarm", |
| 1173 | + {"entity_id": entity_id, "code": "1234"}, |
| 1174 | + blocking=True, |
| 1175 | + ) |
| 1176 | + await hass.async_block_till_done() |
| 1177 | + |
| 1178 | + assert len(events) == 0 |
| 1179 | + |
| 1180 | + with patch("homeassistant.auth.AuthManager.async_get_user") as mock_get_user: |
| 1181 | + mock_user = MagicMock(spec=User) |
| 1182 | + mock_user.id = mock_user_id |
| 1183 | + mock_get_user.return_value = mock_user |
| 1184 | + |
| 1185 | + with pytest.raises(ServiceValidationError): |
| 1186 | + await hass.services.async_call( |
| 1187 | + ALARM_DOMAIN, |
| 1188 | + "alarm_disarm", |
| 1189 | + {"entity_id": entity_id, "code": bad_code}, |
| 1190 | + blocking=True, |
| 1191 | + context=test_context, |
| 1192 | + ) |
| 1193 | + |
| 1194 | + await hass.async_block_till_done() |
| 1195 | + |
| 1196 | + assert len(events) == 1 |
| 1197 | + assert events[0].get("entity_id") == entity_id |
| 1198 | + assert events[0].get("target_state") == AlarmControlPanelState.DISARMED |
| 1199 | + assert events[0].get("user_id") == mock_user_id |
| 1200 | + |
| 1201 | + |
1126 | 1202 | async def test_disarm_with_template_code(hass: HomeAssistant) -> None: |
1127 | 1203 | """Attempt to disarm with a valid or invalid template-based code.""" |
1128 | 1204 | assert await async_setup_component( |
|
0 commit comments