1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
|
from copy import deepcopy
from datetime import datetime
from typing import Any
from unittest.mock import Mock, call, create_autospec
import pytest
from pyschlage.code import AccessCode, DaysOfWeek, RecurringSchedule, TemporarySchedule
from pyschlage.device import Device
from pyschlage.exceptions import NotAuthenticatedError
from pyschlage.notification import Notification
class TestAccessCode:
def test_to_from_json(
self, mock_auth: Mock, access_code_json: dict[str, Any], wifi_device: Device
):
access_code_id = "__access_code_uuid__"
code = AccessCode(
_auth=mock_auth,
_device=wifi_device,
_json=access_code_json,
name="Access code name",
code="0123",
schedule=None,
device_id=wifi_device.device_id,
access_code_id=access_code_id,
)
assert AccessCode.from_json(mock_auth, access_code_json, wifi_device) == code
to_json = code.to_json()
# Access codes returned by the API don't have the `notificationEnabled`` property, but
# we need to pass it when saving an access code.
assert to_json.pop("notificationEnabled") == 0
# We also don't pass the `notification` property when saving an access code, but
# it appears to always be 0 when returned by the API.
access_code_json.pop("notification")
assert to_json == access_code_json
def test_to_from_json_recurring_schedule(
self, mock_auth: Mock, access_code_json: dict[str, Any], wifi_device: Device
):
assert RecurringSchedule.from_json({}) is None
assert RecurringSchedule.from_json(None) is None
access_code_id = "__access_code_uuid__"
sched = RecurringSchedule(days_of_week=DaysOfWeek(mon=False))
json = deepcopy(access_code_json)
json["schedule1"] = sched.to_json()
code = AccessCode(
_auth=mock_auth,
_json=json,
_device=wifi_device,
name="Access code name",
code="0123",
schedule=sched,
device_id=wifi_device.device_id,
access_code_id=access_code_id,
)
assert AccessCode.from_json(mock_auth, json, wifi_device) == code
to_json = code.to_json()
# Access codes returned by the API don't have the `notificationEnabled`` property, but
# we need to pass it when saving an access code.
assert to_json.pop("notificationEnabled") == 0
# We also don't pass the `notification` property when saving an access code, but
# it appears to always be 0 when returned by the API.
json.pop("notification")
assert to_json == json
def test_to_from_json_temporary_schedule(
self, mock_auth: Mock, access_code_json: dict[str, Any], wifi_device: Device
):
access_code_id = "__access_code_uuid__"
sched = TemporarySchedule(
start=datetime(2022, 12, 25, 8, 30, 0),
end=datetime(2022, 12, 25, 9, 0, 0),
)
json = deepcopy(access_code_json)
json["activationSecs"] = 1671957000
json["expirationSecs"] = 1671958800
code = AccessCode(
_auth=mock_auth,
_json=json,
_device=wifi_device,
name="Access code name",
code="0123",
schedule=sched,
device_id=wifi_device.device_id,
access_code_id=access_code_id,
)
assert AccessCode.from_json(mock_auth, json, wifi_device) == code
to_json = code.to_json()
# Access codes returned by the API don't have the `notificationEnabled`` property, but
# we need to pass it when saving an access code.
assert to_json.pop("notificationEnabled") == 0
# We also don't pass the `notification` property when saving an access code, but
# it appears to always be 0 when returned by the API.
json.pop("notification")
assert to_json == json
def test_save(
self,
mock_auth: Mock,
access_code: AccessCode,
notification_json: dict[str, Any],
):
with pytest.raises(NotAuthenticatedError):
AccessCode().save()
access_code.access_code_id = None
notification_json["active"] = False
mock_auth.request.side_effect = [
Mock(json=Mock(return_value={"accesscodeId": "__access_code_uuid__"})),
Mock(json=Mock(return_value=notification_json)),
]
access_code.save()
mock_auth.request.assert_has_calls(
[
call(
"post",
"devices/__wifi_uuid__/commands",
json={
"data": {
"friendlyName": "Access code name",
"accessCode": 123,
"accessCodeLength": 4,
"notificationEnabled": 0,
"disabled": 0,
"activationSecs": 0,
"expirationSecs": 4294967295,
"schedule1": {
"daysOfWeek": "7F",
"startHour": 0,
"startMinute": 0,
"endHour": 23,
"endMinute": 59,
},
},
"name": "addaccesscode",
},
),
call(
"post",
"notifications",
params={"deviceId": "__wifi_uuid__"},
json={
"notificationId": "<user-id>___access_code_uuid__",
"devicetypeId": "be489wifi",
"notificationDefinitionId": "onunlockstateaction",
"active": False,
"filterValue": "Access code name",
},
),
]
)
assert not access_code.notify_on_use
assert access_code._notification is not None
assert not access_code._notification.active
def test_save_new_with_notification(
self,
mock_auth: Mock,
access_code: AccessCode,
notification_json: dict[str, Any],
):
access_code.access_code_id = None
access_code.notify_on_use = True
mock_auth.request.side_effect = [
Mock(json=Mock(return_value={"accesscodeId": "2211"})),
Mock(json=Mock(return_value=notification_json)),
]
access_code.save()
mock_auth.request.assert_has_calls(
[
call(
"post",
"devices/__wifi_uuid__/commands",
json={
"data": {
"friendlyName": "Access code name",
"accessCode": 123,
"accessCodeLength": 4,
"notificationEnabled": 1,
"disabled": 0,
"activationSecs": 0,
"expirationSecs": 4294967295,
"schedule1": {
"daysOfWeek": "7F",
"startHour": 0,
"startMinute": 0,
"endHour": 23,
"endMinute": 59,
},
},
"name": "addaccesscode",
},
),
call(
"post",
"notifications",
params={"deviceId": "__wifi_uuid__"},
json={
"notificationId": "<user-id>_2211",
"devicetypeId": "be489wifi",
"notificationDefinitionId": "onunlockstateaction",
"active": True,
"filterValue": "Access code name",
},
),
]
)
assert access_code.code == "0123"
assert access_code.access_code_id == "2211"
assert access_code.notify_on_use
def test_save_disable_notification(
self,
mock_auth: Mock,
wifi_device: Device,
access_code: AccessCode,
notification: Notification,
notification_json: dict[str, Any],
):
access_code.notify_on_use = False
access_code._notification = notification
notification.device_type = wifi_device.device_type
notification_json["active"] = False
mock_auth.request.side_effect = [
Mock(json=Mock(return_value={"accesscodeId": "__access_code_uuid__"})),
Mock(json=Mock(return_value=notification_json)),
]
access_code.save()
mock_auth.request.assert_has_calls(
[
call(
"post",
"devices/__wifi_uuid__/commands",
json={
"data": {
"friendlyName": "Access code name",
"accessCode": 123,
"accessCodeLength": 4,
"notificationEnabled": 0,
"disabled": 0,
"activationSecs": 0,
"expirationSecs": 4294967295,
"schedule1": {
"daysOfWeek": "7F",
"startHour": 0,
"startMinute": 0,
"endHour": 23,
"endMinute": 59,
},
"accesscodeId": "__access_code_uuid__",
},
"name": "updateaccesscode",
},
),
call(
"put",
"notifications",
params={"deviceId": "__wifi_uuid__"},
json={
"notificationId": "<user-id>___access_code_uuid__",
"devicetypeId": "be489wifi",
"notificationDefinitionId": "onunlockstateaction",
"active": False,
"filterValue": "Access code name",
},
),
]
)
assert not access_code.notify_on_use
assert not notification.active
def test_delete(self, mock_auth: Mock, access_code_json: dict[str, Any]):
with pytest.raises(NotAuthenticatedError):
AccessCode().delete()
mock_device = create_autospec(Device, spec_set=True, device_id="__wifi_uuid__")
code = AccessCode.from_json(mock_auth, access_code_json, mock_device)
mock_notification = create_autospec(Notification, spec_set=True)
code._notification = mock_notification
mock_auth.request.return_value = Mock()
json = code.to_json()
code.delete()
mock_device.send_command.assert_called_once_with("deleteaccesscode", json)
mock_notification.delete.assert_called_once_with()
assert code._auth is None
assert code._json == {}
assert code.access_code_id is None
assert code.disabled
|