Test rework + add account & fmi device test (#266)
* Rework tests * Add account test * Add Find My iPhone devices test * Remove logger * Working with Python 3.4 * Make test working in more setups @patch("keyring.get_password", return_value=None) * Fix Python 2.7 ASCII * Pylint * Self reviewed
This commit is contained in:
parent
d510b14570
commit
91ac1d956e
9 changed files with 1868 additions and 194 deletions
|
@ -56,9 +56,9 @@ class PyiCloudSession(Session):
|
|||
|
||||
def __init__(self, service):
|
||||
self.service = service
|
||||
super(PyiCloudSession, self).__init__()
|
||||
Session.__init__(self)
|
||||
|
||||
def request(self, *args, **kwargs): # pylint: disable=arguments-differ
|
||||
def request(self, method, url, **kwargs): # pylint: disable=arguments-differ
|
||||
|
||||
# Charge logging to the right service endpoint
|
||||
callee = inspect.stack()[2]
|
||||
|
@ -67,10 +67,10 @@ class PyiCloudSession(Session):
|
|||
if self.service.password_filter not in request_logger.filters:
|
||||
request_logger.addFilter(self.service.password_filter)
|
||||
|
||||
request_logger.debug("%s %s %s", args[0], args[1], kwargs.get("data", ""))
|
||||
request_logger.debug("%s %s %s", method, url, kwargs.get("data", ""))
|
||||
|
||||
kwargs.pop("retried", None)
|
||||
response = super(PyiCloudSession, self).request(*args, **kwargs)
|
||||
response = super(PyiCloudSession, self).request(method, url, **kwargs)
|
||||
|
||||
content_type = response.headers.get("Content-Type", "").split(";")[0]
|
||||
json_mimetypes = ["application/json", "text/json"]
|
||||
|
@ -82,7 +82,7 @@ class PyiCloudSession(Session):
|
|||
)
|
||||
request_logger.warn(api_error)
|
||||
kwargs["retried"] = True
|
||||
return self.request(*args, **kwargs)
|
||||
return self.request(method, url, **kwargs)
|
||||
self._raise_error(response.status_code, response.reason)
|
||||
|
||||
if content_type not in json_mimetypes:
|
||||
|
@ -150,6 +150,9 @@ class PyiCloudService(object):
|
|||
pyicloud.iphone.location()
|
||||
"""
|
||||
|
||||
HOME_ENDPOINT = "https://www.icloud.com"
|
||||
SETUP_ENDPOINT = "https://setup.icloud.com/setup/ws/1"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
apple_id,
|
||||
|
@ -170,10 +173,7 @@ class PyiCloudService(object):
|
|||
self.password_filter = PyiCloudPasswordFilter(password)
|
||||
LOGGER.addFilter(self.password_filter)
|
||||
|
||||
self._home_endpoint = "https://www.icloud.com"
|
||||
self._setup_endpoint = "https://setup.icloud.com/setup/ws/1"
|
||||
|
||||
self._base_login_url = "%s/login" % self._setup_endpoint
|
||||
self._base_login_url = "%s/login" % self.SETUP_ENDPOINT
|
||||
|
||||
if cookie_directory:
|
||||
self._cookie_directory = os.path.expanduser(
|
||||
|
@ -186,8 +186,8 @@ class PyiCloudService(object):
|
|||
self.session.verify = verify
|
||||
self.session.headers.update(
|
||||
{
|
||||
"Origin": self._home_endpoint,
|
||||
"Referer": "%s/" % self._home_endpoint,
|
||||
"Origin": self.HOME_ENDPOINT,
|
||||
"Referer": "%s/" % self.HOME_ENDPOINT,
|
||||
"User-Agent": "Opera/9.52 (X11; Linux i686; U; en)",
|
||||
}
|
||||
)
|
||||
|
@ -270,7 +270,7 @@ class PyiCloudService(object):
|
|||
def trusted_devices(self):
|
||||
"""Returns devices trusted for two-step authentication."""
|
||||
request = self.session.get(
|
||||
"%s/listDevices" % self._setup_endpoint, params=self.params
|
||||
"%s/listDevices" % self.SETUP_ENDPOINT, params=self.params
|
||||
)
|
||||
return request.json().get("devices")
|
||||
|
||||
|
@ -278,7 +278,7 @@ class PyiCloudService(object):
|
|||
"""Requests that a verification code is sent to the given device."""
|
||||
data = json.dumps(device)
|
||||
request = self.session.post(
|
||||
"%s/sendVerificationCode" % self._setup_endpoint,
|
||||
"%s/sendVerificationCode" % self.SETUP_ENDPOINT,
|
||||
params=self.params,
|
||||
data=data,
|
||||
)
|
||||
|
@ -291,7 +291,7 @@ class PyiCloudService(object):
|
|||
|
||||
try:
|
||||
self.session.post(
|
||||
"%s/validateVerificationCode" % self._setup_endpoint,
|
||||
"%s/validateVerificationCode" % self.SETUP_ENDPOINT,
|
||||
params=self.params,
|
||||
data=data,
|
||||
)
|
||||
|
|
|
@ -1,13 +1,87 @@
|
|||
"""Library tests."""
|
||||
import json
|
||||
from requests import Session, Response
|
||||
|
||||
from pyicloud import base
|
||||
from pyicloud.exceptions import PyiCloudFailedLoginException
|
||||
from pyicloud.services.findmyiphone import FindMyiPhoneServiceManager, AppleDevice
|
||||
|
||||
from .const import (
|
||||
AUTHENTICATED_USER,
|
||||
REQUIRES_2SA_USER,
|
||||
VALID_USERS,
|
||||
VALID_PASSWORD,
|
||||
)
|
||||
from .const_login import (
|
||||
LOGIN_WORKING,
|
||||
LOGIN_2SA,
|
||||
TRUSTED_DEVICES,
|
||||
TRUSTED_DEVICE_1,
|
||||
VERIFICATION_CODE_OK,
|
||||
VERIFICATION_CODE_KO,
|
||||
)
|
||||
from .const_account import ACCOUNT_DEVICES_WORKING
|
||||
from .const_findmyiphone import FMI_FMLY_WORKING
|
||||
|
||||
AUTHENTICATED_USER = "authenticated_user"
|
||||
REQUIRES_2SA_USER = "requires_2sa_user"
|
||||
VALID_USERS = [AUTHENTICATED_USER, REQUIRES_2SA_USER]
|
||||
|
||||
class ResponseMock(Response):
|
||||
"""Mocked Response."""
|
||||
|
||||
def __init__(self, result, status_code=200):
|
||||
Response.__init__(self)
|
||||
self.result = result
|
||||
self.status_code = status_code
|
||||
|
||||
@property
|
||||
def text(self):
|
||||
return json.dumps(self.result)
|
||||
|
||||
|
||||
class PyiCloudSessionMock(base.PyiCloudSession):
|
||||
"""Mocked PyiCloudSession."""
|
||||
|
||||
def request(self, method, url, **kwargs):
|
||||
data = json.loads(kwargs.get("data", "{}"))
|
||||
|
||||
# Login
|
||||
if self.service.SETUP_ENDPOINT in url:
|
||||
if "login" in url and method == "POST":
|
||||
if (
|
||||
data.get("apple_id") not in VALID_USERS
|
||||
or data.get("password") != VALID_PASSWORD
|
||||
):
|
||||
self._raise_error(None, "Unknown reason")
|
||||
if (
|
||||
data.get("apple_id") == REQUIRES_2SA_USER
|
||||
and data.get("password") == VALID_PASSWORD
|
||||
):
|
||||
return ResponseMock(LOGIN_2SA)
|
||||
return ResponseMock(LOGIN_WORKING)
|
||||
|
||||
if "listDevices" in url and method == "GET":
|
||||
return ResponseMock(TRUSTED_DEVICES)
|
||||
|
||||
if "sendVerificationCode" in url and method == "POST":
|
||||
if data == TRUSTED_DEVICE_1:
|
||||
return ResponseMock(VERIFICATION_CODE_OK)
|
||||
return ResponseMock(VERIFICATION_CODE_KO)
|
||||
|
||||
if "validateVerificationCode" in url and method == "POST":
|
||||
TRUSTED_DEVICE_1.update({"verificationCode": "0", "trustBrowser": True})
|
||||
if data == TRUSTED_DEVICE_1:
|
||||
self.service.user["apple_id"] = AUTHENTICATED_USER
|
||||
return ResponseMock(VERIFICATION_CODE_OK)
|
||||
self._raise_error(None, "FOUND_CODE")
|
||||
|
||||
# Account
|
||||
if "device/getDevices" in url and method == "GET":
|
||||
return ResponseMock(ACCOUNT_DEVICES_WORKING)
|
||||
|
||||
# Find My iPhone
|
||||
if "fmi" in url and method == "POST":
|
||||
return ResponseMock(FMI_FMLY_WORKING)
|
||||
|
||||
return None
|
||||
|
||||
|
||||
class PyiCloudServiceMock(base.PyiCloudService):
|
||||
|
@ -22,174 +96,7 @@ class PyiCloudServiceMock(base.PyiCloudService):
|
|||
client_id=None,
|
||||
with_family=True,
|
||||
):
|
||||
base.PyiCloudSession = PyiCloudSessionMock
|
||||
base.PyiCloudService.__init__(
|
||||
self, apple_id, password, cookie_directory, verify, client_id, with_family
|
||||
)
|
||||
base.FindMyiPhoneServiceManager = FindMyiPhoneServiceManagerMock
|
||||
|
||||
def authenticate(self):
|
||||
if (
|
||||
not self.user.get("apple_id")
|
||||
or self.user.get("apple_id") not in VALID_USERS
|
||||
):
|
||||
raise PyiCloudFailedLoginException(
|
||||
"Invalid email/password combination.", None
|
||||
)
|
||||
if not self.user.get("password") or self.user.get("password") != "valid_pass":
|
||||
raise PyiCloudFailedLoginException(
|
||||
"Invalid email/password combination.", None
|
||||
)
|
||||
|
||||
self.params.update({"dsid": "ID"})
|
||||
self._webservices = {
|
||||
"account": {"url": "account_url",},
|
||||
"findme": {"url": "findme_url",},
|
||||
"calendar": {"url": "calendar_url",},
|
||||
"contacts": {"url": "contacts_url",},
|
||||
"reminders": {"url": "reminders_url",},
|
||||
}
|
||||
|
||||
@property
|
||||
def requires_2sa(self):
|
||||
return self.user["apple_id"] is REQUIRES_2SA_USER
|
||||
|
||||
@property
|
||||
def trusted_devices(self):
|
||||
return [
|
||||
{
|
||||
"deviceType": "SMS",
|
||||
"areaCode": "",
|
||||
"phoneNumber": "*******58",
|
||||
"deviceId": "1",
|
||||
}
|
||||
]
|
||||
|
||||
def send_verification_code(self, device):
|
||||
return device
|
||||
|
||||
def validate_verification_code(self, device, code):
|
||||
if not device or code != 0:
|
||||
self.user["apple_id"] = AUTHENTICATED_USER
|
||||
self.authenticate()
|
||||
return not self.requires_2sa
|
||||
|
||||
|
||||
IPHONE_DEVICE_ID = "X1x/X&x="
|
||||
IPHONE_DEVICE = AppleDevice(
|
||||
{
|
||||
"msg": {
|
||||
"strobe": False,
|
||||
"userText": False,
|
||||
"playSound": True,
|
||||
"vibrate": True,
|
||||
"createTimestamp": 1568031021347,
|
||||
"statusCode": "200",
|
||||
},
|
||||
"canWipeAfterLock": True,
|
||||
"baUUID": "",
|
||||
"wipeInProgress": False,
|
||||
"lostModeEnabled": False,
|
||||
"activationLocked": True,
|
||||
"passcodeLength": 6,
|
||||
"deviceStatus": "200",
|
||||
"deviceColor": "1-6-0",
|
||||
"features": {
|
||||
"MSG": True,
|
||||
"LOC": True,
|
||||
"LLC": False,
|
||||
"CLK": False,
|
||||
"TEU": True,
|
||||
"LMG": False,
|
||||
"SND": True,
|
||||
"CLT": False,
|
||||
"LKL": False,
|
||||
"SVP": False,
|
||||
"LST": True,
|
||||
"LKM": False,
|
||||
"WMG": True,
|
||||
"SPN": False,
|
||||
"XRM": False,
|
||||
"PIN": False,
|
||||
"LCK": True,
|
||||
"REM": False,
|
||||
"MCS": False,
|
||||
"CWP": False,
|
||||
"KEY": False,
|
||||
"KPD": False,
|
||||
"WIP": True,
|
||||
},
|
||||
"lowPowerMode": True,
|
||||
"rawDeviceModel": "iPhone11,8",
|
||||
"id": IPHONE_DEVICE_ID,
|
||||
"remoteLock": None,
|
||||
"isLocating": True,
|
||||
"modelDisplayName": "iPhone",
|
||||
"lostTimestamp": "",
|
||||
"batteryLevel": 0.47999998927116394,
|
||||
"mesg": None,
|
||||
"locationEnabled": True,
|
||||
"lockedTimestamp": None,
|
||||
"locFoundEnabled": False,
|
||||
"snd": {"createTimestamp": 1568031021347, "statusCode": "200"},
|
||||
"fmlyShare": False,
|
||||
"lostDevice": {
|
||||
"stopLostMode": False,
|
||||
"emailUpdates": False,
|
||||
"userText": True,
|
||||
"sound": False,
|
||||
"ownerNbr": "",
|
||||
"text": "",
|
||||
"createTimestamp": 1558383841233,
|
||||
"statusCode": "2204",
|
||||
},
|
||||
"lostModeCapable": True,
|
||||
"wipedTimestamp": None,
|
||||
"deviceDisplayName": "iPhone XR",
|
||||
"prsId": None,
|
||||
"audioChannels": [],
|
||||
"locationCapable": True,
|
||||
"batteryStatus": "NotCharging",
|
||||
"trackingInfo": None,
|
||||
"name": "Quentin's iPhone",
|
||||
"isMac": False,
|
||||
"thisDevice": False,
|
||||
"deviceClass": "iPhone",
|
||||
"location": {
|
||||
"isOld": False,
|
||||
"isInaccurate": False,
|
||||
"altitude": 0.0,
|
||||
"positionType": "GPS",
|
||||
"latitude": 46.012345678,
|
||||
"floorLevel": 0,
|
||||
"horizontalAccuracy": 12.012345678,
|
||||
"locationType": "",
|
||||
"timeStamp": 1568827039692,
|
||||
"locationFinished": False,
|
||||
"verticalAccuracy": 0.0,
|
||||
"longitude": 5.012345678,
|
||||
},
|
||||
"deviceModel": "iphoneXR-1-6-0",
|
||||
"maxMsgChar": 160,
|
||||
"darkWake": False,
|
||||
"remoteWipe": None,
|
||||
},
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
|
||||
DEVICES = {
|
||||
IPHONE_DEVICE_ID: IPHONE_DEVICE,
|
||||
}
|
||||
|
||||
|
||||
class FindMyiPhoneServiceManagerMock(FindMyiPhoneServiceManager):
|
||||
"""Mocked FindMyiPhoneServiceManager."""
|
||||
|
||||
def __init__(self, service_root, session, params, with_family=False):
|
||||
FindMyiPhoneServiceManager.__init__(
|
||||
self, service_root, session, params, with_family
|
||||
)
|
||||
|
||||
def refresh_client(self):
|
||||
self._devices = DEVICES
|
||||
|
|
10
tests/const.py
Normal file
10
tests/const.py
Normal file
|
@ -0,0 +1,10 @@
|
|||
"""Test constants."""
|
||||
from .const_login import PRIMARY_EMAIL, APPLE_ID_EMAIL, ICLOUD_ID_EMAIL
|
||||
|
||||
# Base
|
||||
AUTHENTICATED_USER = PRIMARY_EMAIL
|
||||
REQUIRES_2SA_USER = "requires_2sa_user"
|
||||
VALID_USERS = [AUTHENTICATED_USER, REQUIRES_2SA_USER, APPLE_ID_EMAIL, ICLOUD_ID_EMAIL]
|
||||
VALID_PASSWORD = "valid_password"
|
||||
|
||||
CLIENT_ID = "client_id"
|
77
tests/const_account.py
Normal file
77
tests/const_account.py
Normal file
|
@ -0,0 +1,77 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Account test constants."""
|
||||
from .const_login import FIRST_NAME
|
||||
|
||||
# Fakers
|
||||
PAYMENT_METHOD_ID_1 = "PAYMENT_METHOD_ID_1"
|
||||
PAYMENT_METHOD_ID_2 = "PAYMENT_METHOD_ID_2"
|
||||
PAYMENT_METHOD_ID_3 = "PAYMENT_METHOD_ID_3"
|
||||
PAYMENT_METHOD_ID_4 = "PAYMENT_METHOD_ID_4"
|
||||
|
||||
# Data
|
||||
ACCOUNT_DEVICES_WORKING = {
|
||||
"devices": [
|
||||
{
|
||||
"serialNumber": "●●●●●●●NG123",
|
||||
"osVersion": "OSX;10.15.3",
|
||||
"modelLargePhotoURL2x": "https://statici.icloud.com/fmipmobile/deviceImages-4.0/MacBookPro/MacBookPro15,1-spacegray/online-infobox__2x.png",
|
||||
"modelLargePhotoURL1x": "https://statici.icloud.com/fmipmobile/deviceImages-4.0/MacBookPro/MacBookPro15,1-spacegray/online-infobox.png",
|
||||
"paymentMethods": [PAYMENT_METHOD_ID_3],
|
||||
"name": "MacBook Pro de " + FIRST_NAME,
|
||||
"imei": "",
|
||||
"model": "MacBookPro15,1",
|
||||
"udid": "MacBookPro15,1" + FIRST_NAME,
|
||||
"modelSmallPhotoURL2x": "https://statici.icloud.com/fmipmobile/deviceImages-4.0/MacBookPro/MacBookPro15,1-spacegray/online-sourcelist__2x.png",
|
||||
"modelSmallPhotoURL1x": "https://statici.icloud.com/fmipmobile/deviceImages-4.0/MacBookPro/MacBookPro15,1-spacegray/online-sourcelist.png",
|
||||
"modelDisplayName": 'MacBook Pro 15"',
|
||||
},
|
||||
{
|
||||
"serialNumber": "●●●●●●●UX123",
|
||||
"osVersion": "iOS;13.3",
|
||||
"modelLargePhotoURL2x": "https://statici.icloud.com/fmipmobile/deviceImages-4.0/iPhone/iPhone12,1-1-6-0/online-infobox__2x.png",
|
||||
"modelLargePhotoURL1x": "https://statici.icloud.com/fmipmobile/deviceImages-4.0/iPhone/iPhone12,1-1-6-0/online-infobox.png",
|
||||
"paymentMethods": [
|
||||
PAYMENT_METHOD_ID_4,
|
||||
PAYMENT_METHOD_ID_2,
|
||||
PAYMENT_METHOD_ID_1,
|
||||
],
|
||||
"name": "iPhone de " + FIRST_NAME,
|
||||
"imei": "●●●●●●●●●●12345",
|
||||
"model": "iPhone12,1",
|
||||
"udid": "iPhone12,1" + FIRST_NAME,
|
||||
"modelSmallPhotoURL2x": "https://statici.icloud.com/fmipmobile/deviceImages-4.0/iPhone/iPhone12,1-1-6-0/online-sourcelist__2x.png",
|
||||
"modelSmallPhotoURL1x": "https://statici.icloud.com/fmipmobile/deviceImages-4.0/iPhone/iPhone12,1-1-6-0/online-sourcelist.png",
|
||||
"modelDisplayName": "iPhone 11",
|
||||
},
|
||||
],
|
||||
"paymentMethods": [
|
||||
{
|
||||
"lastFourDigits": "333",
|
||||
"balanceStatus": "NOTAPPLICABLE",
|
||||
"suspensionReason": "ACTIVE",
|
||||
"id": PAYMENT_METHOD_ID_3,
|
||||
"type": "Boursorama Banque",
|
||||
},
|
||||
{
|
||||
"lastFourDigits": "444",
|
||||
"balanceStatus": "NOTAPPLICABLE",
|
||||
"suspensionReason": "ACTIVE",
|
||||
"id": PAYMENT_METHOD_ID_4,
|
||||
"type": "Carte Crédit Agricole",
|
||||
},
|
||||
{
|
||||
"lastFourDigits": "2222",
|
||||
"balanceStatus": "NOTAPPLICABLE",
|
||||
"suspensionReason": "ACTIVE",
|
||||
"id": PAYMENT_METHOD_ID_2,
|
||||
"type": "Lydia",
|
||||
},
|
||||
{
|
||||
"lastFourDigits": "111",
|
||||
"balanceStatus": "NOTAPPLICABLE",
|
||||
"suspensionReason": "ACTIVE",
|
||||
"id": PAYMENT_METHOD_ID_1,
|
||||
"type": "Boursorama Banque",
|
||||
},
|
||||
],
|
||||
}
|
1136
tests/const_findmyiphone.py
Normal file
1136
tests/const_findmyiphone.py
Normal file
File diff suppressed because it is too large
Load diff
413
tests/const_login.py
Normal file
413
tests/const_login.py
Normal file
|
@ -0,0 +1,413 @@
|
|||
"""Login test constants."""
|
||||
|
||||
# Base
|
||||
FIRST_NAME = "Quentin"
|
||||
LAST_NAME = "TARANTINO"
|
||||
FULL_NAME = FIRST_NAME + " " + LAST_NAME
|
||||
|
||||
PERSON_ID = (FIRST_NAME + LAST_NAME).lower()
|
||||
NOTIFICATION_ID = "12345678-1234-1234-1234-123456789012" + PERSON_ID
|
||||
A_DS_ID = "123456-12-12345678-1234-1234-1234-123456789012" + PERSON_ID
|
||||
WIDGET_KEY = "widget_key" + PERSON_ID
|
||||
|
||||
PRIMARY_EMAIL = PERSON_ID + "@hotmail.fr"
|
||||
APPLE_ID_EMAIL = PERSON_ID + "@me.com"
|
||||
ICLOUD_ID_EMAIL = PERSON_ID + "@icloud.com"
|
||||
|
||||
|
||||
# Data
|
||||
LOGIN_WORKING = {
|
||||
"dsInfo": {
|
||||
"lastName": LAST_NAME,
|
||||
"iCDPEnabled": False,
|
||||
"tantorMigrated": True,
|
||||
"dsid": PERSON_ID,
|
||||
"hsaEnabled": True,
|
||||
"ironcadeMigrated": True,
|
||||
"locale": "fr-fr_FR",
|
||||
"brZoneConsolidated": False,
|
||||
"isManagedAppleID": False,
|
||||
"gilligan-invited": "true",
|
||||
"appleIdAliases": [APPLE_ID_EMAIL, ICLOUD_ID_EMAIL],
|
||||
"hsaVersion": 2,
|
||||
"isPaidDeveloper": False,
|
||||
"countryCode": "FRA",
|
||||
"notificationId": NOTIFICATION_ID,
|
||||
"primaryEmailVerified": True,
|
||||
"aDsID": A_DS_ID,
|
||||
"locked": False,
|
||||
"hasICloudQualifyingDevice": True,
|
||||
"primaryEmail": PRIMARY_EMAIL,
|
||||
"appleIdEntries": [
|
||||
{"isPrimary": True, "type": "EMAIL", "value": PRIMARY_EMAIL},
|
||||
{"type": "EMAIL", "value": APPLE_ID_EMAIL},
|
||||
{"type": "EMAIL", "value": ICLOUD_ID_EMAIL},
|
||||
],
|
||||
"gilligan-enabled": "true",
|
||||
"fullName": FULL_NAME,
|
||||
"languageCode": "fr-fr",
|
||||
"appleId": PRIMARY_EMAIL,
|
||||
"firstName": FIRST_NAME,
|
||||
"iCloudAppleIdAlias": ICLOUD_ID_EMAIL,
|
||||
"notesMigrated": True,
|
||||
"hasPaymentInfo": False,
|
||||
"pcsDeleted": False,
|
||||
"appleIdAlias": APPLE_ID_EMAIL,
|
||||
"brMigrated": True,
|
||||
"statusCode": 2,
|
||||
"familyEligible": True,
|
||||
},
|
||||
"hasMinimumDeviceForPhotosWeb": True,
|
||||
"iCDPEnabled": False,
|
||||
"webservices": {
|
||||
"reminders": {
|
||||
"url": "https://p31-remindersws.icloud.com:443",
|
||||
"status": "active",
|
||||
},
|
||||
"notes": {"url": "https://p38-notesws.icloud.com:443", "status": "active"},
|
||||
"mail": {"url": "https://p38-mailws.icloud.com:443", "status": "active"},
|
||||
"ckdatabasews": {
|
||||
"pcsRequired": True,
|
||||
"url": "https://p31-ckdatabasews.icloud.com:443",
|
||||
"status": "active",
|
||||
},
|
||||
"photosupload": {
|
||||
"pcsRequired": True,
|
||||
"url": "https://p31-uploadphotosws.icloud.com:443",
|
||||
"status": "active",
|
||||
},
|
||||
"photos": {
|
||||
"pcsRequired": True,
|
||||
"uploadUrl": "https://p31-uploadphotosws.icloud.com:443",
|
||||
"url": "https://p31-photosws.icloud.com:443",
|
||||
"status": "active",
|
||||
},
|
||||
"drivews": {
|
||||
"pcsRequired": True,
|
||||
"url": "https://p31-drivews.icloud.com:443",
|
||||
"status": "active",
|
||||
},
|
||||
"uploadimagews": {
|
||||
"url": "https://p31-uploadimagews.icloud.com:443",
|
||||
"status": "active",
|
||||
},
|
||||
"schoolwork": {},
|
||||
"cksharews": {"url": "https://p31-ckshare.icloud.com:443", "status": "active"},
|
||||
"findme": {"url": "https://p31-fmipweb.icloud.com:443", "status": "active"},
|
||||
"ckdeviceservice": {"url": "https://p31-ckdevice.icloud.com:443"},
|
||||
"iworkthumbnailws": {
|
||||
"url": "https://p31-iworkthumbnailws.icloud.com:443",
|
||||
"status": "active",
|
||||
},
|
||||
"calendar": {
|
||||
"url": "https://p31-calendarws.icloud.com:443",
|
||||
"status": "active",
|
||||
},
|
||||
"docws": {
|
||||
"pcsRequired": True,
|
||||
"url": "https://p31-docws.icloud.com:443",
|
||||
"status": "active",
|
||||
},
|
||||
"settings": {
|
||||
"url": "https://p31-settingsws.icloud.com:443",
|
||||
"status": "active",
|
||||
},
|
||||
"ubiquity": {
|
||||
"url": "https://p31-ubiquityws.icloud.com:443",
|
||||
"status": "active",
|
||||
},
|
||||
"streams": {"url": "https://p31-streams.icloud.com:443", "status": "active"},
|
||||
"keyvalue": {
|
||||
"url": "https://p31-keyvalueservice.icloud.com:443",
|
||||
"status": "active",
|
||||
},
|
||||
"archivews": {
|
||||
"url": "https://p31-archivews.icloud.com:443",
|
||||
"status": "active",
|
||||
},
|
||||
"push": {"url": "https://p31-pushws.icloud.com:443", "status": "active"},
|
||||
"iwmb": {"url": "https://p31-iwmb.icloud.com:443", "status": "active"},
|
||||
"iworkexportws": {
|
||||
"url": "https://p31-iworkexportws.icloud.com:443",
|
||||
"status": "active",
|
||||
},
|
||||
"geows": {"url": "https://p31-geows.icloud.com:443", "status": "active"},
|
||||
"account": {
|
||||
"iCloudEnv": {"shortId": "p", "vipSuffix": "prod"},
|
||||
"url": "https://p31-setup.icloud.com:443",
|
||||
"status": "active",
|
||||
},
|
||||
"fmf": {"url": "https://p31-fmfweb.icloud.com:443", "status": "active"},
|
||||
"contacts": {
|
||||
"url": "https://p31-contactsws.icloud.com:443",
|
||||
"status": "active",
|
||||
},
|
||||
},
|
||||
"pcsEnabled": True,
|
||||
"configBag": {
|
||||
"urls": {
|
||||
"accountCreateUI": "https://appleid.apple.com/widget/account/?widgetKey="
|
||||
+ WIDGET_KEY
|
||||
+ "#!create",
|
||||
"accountLoginUI": "https://idmsa.apple.com/appleauth/auth/signin?widgetKey="
|
||||
+ WIDGET_KEY,
|
||||
"accountLogin": "https://setup.icloud.com/setup/ws/1/accountLogin",
|
||||
"accountRepairUI": "https://appleid.apple.com/widget/account/?widgetKey="
|
||||
+ WIDGET_KEY
|
||||
+ "#!repair",
|
||||
"downloadICloudTerms": "https://setup.icloud.com/setup/ws/1/downloadLiteTerms",
|
||||
"repairDone": "https://setup.icloud.com/setup/ws/1/repairDone",
|
||||
"accountAuthorizeUI": "https://idmsa.apple.com/appleauth/auth/authorize/signin?client_id="
|
||||
+ WIDGET_KEY,
|
||||
"vettingUrlForEmail": "https://id.apple.com/IDMSEmailVetting/vetShareEmail",
|
||||
"accountCreate": "https://setup.icloud.com/setup/ws/1/createLiteAccount",
|
||||
"getICloudTerms": "https://setup.icloud.com/setup/ws/1/getTerms",
|
||||
"vettingUrlForPhone": "https://id.apple.com/IDMSEmailVetting/vetSharePhone",
|
||||
},
|
||||
"accountCreateEnabled": "true",
|
||||
},
|
||||
"hsaTrustedBrowser": True,
|
||||
"appsOrder": [
|
||||
"mail",
|
||||
"contacts",
|
||||
"calendar",
|
||||
"photos",
|
||||
"iclouddrive",
|
||||
"notes3",
|
||||
"reminders",
|
||||
"pages",
|
||||
"numbers",
|
||||
"keynote",
|
||||
"newspublisher",
|
||||
"fmf",
|
||||
"find",
|
||||
"settings",
|
||||
],
|
||||
"version": 2,
|
||||
"isExtendedLogin": False,
|
||||
"pcsServiceIdentitiesIncluded": True,
|
||||
"hsaChallengeRequired": False,
|
||||
"requestInfo": {"country": "FR", "timeZone": "GMT+1", "region": "IDF"},
|
||||
"pcsDeleted": False,
|
||||
"iCloudInfo": {"SafariBookmarksHasMigratedToCloudKit": True},
|
||||
"apps": {
|
||||
"calendar": {},
|
||||
"reminders": {},
|
||||
"keynote": {"isQualifiedForBeta": True},
|
||||
"settings": {"canLaunchWithOneFactor": True},
|
||||
"mail": {},
|
||||
"numbers": {"isQualifiedForBeta": True},
|
||||
"photos": {},
|
||||
"pages": {"isQualifiedForBeta": True},
|
||||
"notes3": {},
|
||||
"find": {"canLaunchWithOneFactor": True},
|
||||
"iclouddrive": {},
|
||||
"newspublisher": {"isHidden": True},
|
||||
"fmf": {},
|
||||
"contacts": {},
|
||||
},
|
||||
}
|
||||
|
||||
# Setup data
|
||||
LOGIN_2SA = {
|
||||
"dsInfo": {
|
||||
"lastName": LAST_NAME,
|
||||
"iCDPEnabled": False,
|
||||
"tantorMigrated": True,
|
||||
"dsid": PERSON_ID,
|
||||
"hsaEnabled": True,
|
||||
"ironcadeMigrated": True,
|
||||
"locale": "fr-fr_FR",
|
||||
"brZoneConsolidated": False,
|
||||
"isManagedAppleID": False,
|
||||
"gilligan-invited": "true",
|
||||
"appleIdAliases": [APPLE_ID_EMAIL, ICLOUD_ID_EMAIL],
|
||||
"hsaVersion": 2,
|
||||
"isPaidDeveloper": False,
|
||||
"countryCode": "FRA",
|
||||
"notificationId": NOTIFICATION_ID,
|
||||
"primaryEmailVerified": True,
|
||||
"aDsID": A_DS_ID,
|
||||
"locked": False,
|
||||
"hasICloudQualifyingDevice": True,
|
||||
"primaryEmail": PRIMARY_EMAIL,
|
||||
"appleIdEntries": [
|
||||
{"isPrimary": True, "type": "EMAIL", "value": PRIMARY_EMAIL},
|
||||
{"type": "EMAIL", "value": APPLE_ID_EMAIL},
|
||||
{"type": "EMAIL", "value": ICLOUD_ID_EMAIL},
|
||||
],
|
||||
"gilligan-enabled": "true",
|
||||
"fullName": FULL_NAME,
|
||||
"languageCode": "fr-fr",
|
||||
"appleId": PRIMARY_EMAIL,
|
||||
"firstName": FIRST_NAME,
|
||||
"iCloudAppleIdAlias": ICLOUD_ID_EMAIL,
|
||||
"notesMigrated": True,
|
||||
"hasPaymentInfo": True,
|
||||
"pcsDeleted": False,
|
||||
"appleIdAlias": APPLE_ID_EMAIL,
|
||||
"brMigrated": True,
|
||||
"statusCode": 2,
|
||||
"familyEligible": True,
|
||||
},
|
||||
"hasMinimumDeviceForPhotosWeb": True,
|
||||
"iCDPEnabled": False,
|
||||
"webservices": {
|
||||
"reminders": {
|
||||
"url": "https://p31-remindersws.icloud.com:443",
|
||||
"status": "active",
|
||||
},
|
||||
"notes": {"url": "https://p38-notesws.icloud.com:443", "status": "active"},
|
||||
"mail": {"url": "https://p38-mailws.icloud.com:443", "status": "active"},
|
||||
"ckdatabasews": {
|
||||
"pcsRequired": True,
|
||||
"url": "https://p31-ckdatabasews.icloud.com:443",
|
||||
"status": "active",
|
||||
},
|
||||
"photosupload": {
|
||||
"pcsRequired": True,
|
||||
"url": "https://p31-uploadphotosws.icloud.com:443",
|
||||
"status": "active",
|
||||
},
|
||||
"photos": {
|
||||
"pcsRequired": True,
|
||||
"uploadUrl": "https://p31-uploadphotosws.icloud.com:443",
|
||||
"url": "https://p31-photosws.icloud.com:443",
|
||||
"status": "active",
|
||||
},
|
||||
"drivews": {
|
||||
"pcsRequired": True,
|
||||
"url": "https://p31-drivews.icloud.com:443",
|
||||
"status": "active",
|
||||
},
|
||||
"uploadimagews": {
|
||||
"url": "https://p31-uploadimagews.icloud.com:443",
|
||||
"status": "active",
|
||||
},
|
||||
"schoolwork": {},
|
||||
"cksharews": {"url": "https://p31-ckshare.icloud.com:443", "status": "active"},
|
||||
"findme": {"url": "https://p31-fmipweb.icloud.com:443", "status": "active"},
|
||||
"ckdeviceservice": {"url": "https://p31-ckdevice.icloud.com:443"},
|
||||
"iworkthumbnailws": {
|
||||
"url": "https://p31-iworkthumbnailws.icloud.com:443",
|
||||
"status": "active",
|
||||
},
|
||||
"calendar": {
|
||||
"url": "https://p31-calendarws.icloud.com:443",
|
||||
"status": "active",
|
||||
},
|
||||
"docws": {
|
||||
"pcsRequired": True,
|
||||
"url": "https://p31-docws.icloud.com:443",
|
||||
"status": "active",
|
||||
},
|
||||
"settings": {
|
||||
"url": "https://p31-settingsws.icloud.com:443",
|
||||
"status": "active",
|
||||
},
|
||||
"ubiquity": {
|
||||
"url": "https://p31-ubiquityws.icloud.com:443",
|
||||
"status": "active",
|
||||
},
|
||||
"streams": {"url": "https://p31-streams.icloud.com:443", "status": "active"},
|
||||
"keyvalue": {
|
||||
"url": "https://p31-keyvalueservice.icloud.com:443",
|
||||
"status": "active",
|
||||
},
|
||||
"archivews": {
|
||||
"url": "https://p31-archivews.icloud.com:443",
|
||||
"status": "active",
|
||||
},
|
||||
"push": {"url": "https://p31-pushws.icloud.com:443", "status": "active"},
|
||||
"iwmb": {"url": "https://p31-iwmb.icloud.com:443", "status": "active"},
|
||||
"iworkexportws": {
|
||||
"url": "https://p31-iworkexportws.icloud.com:443",
|
||||
"status": "active",
|
||||
},
|
||||
"geows": {"url": "https://p31-geows.icloud.com:443", "status": "active"},
|
||||
"account": {
|
||||
"iCloudEnv": {"shortId": "p", "vipSuffix": "prod"},
|
||||
"url": "https://p31-setup.icloud.com:443",
|
||||
"status": "active",
|
||||
},
|
||||
"fmf": {"url": "https://p31-fmfweb.icloud.com:443", "status": "active"},
|
||||
"contacts": {
|
||||
"url": "https://p31-contactsws.icloud.com:443",
|
||||
"status": "active",
|
||||
},
|
||||
},
|
||||
"pcsEnabled": True,
|
||||
"configBag": {
|
||||
"urls": {
|
||||
"accountCreateUI": "https://appleid.apple.com/widget/account/?widgetKey="
|
||||
+ WIDGET_KEY
|
||||
+ "#!create",
|
||||
"accountLoginUI": "https://idmsa.apple.com/appleauth/auth/signin?widgetKey="
|
||||
+ WIDGET_KEY,
|
||||
"accountLogin": "https://setup.icloud.com/setup/ws/1/accountLogin",
|
||||
"accountRepairUI": "https://appleid.apple.com/widget/account/?widgetKey="
|
||||
+ WIDGET_KEY
|
||||
+ "#!repair",
|
||||
"downloadICloudTerms": "https://setup.icloud.com/setup/ws/1/downloadLiteTerms",
|
||||
"repairDone": "https://setup.icloud.com/setup/ws/1/repairDone",
|
||||
"accountAuthorizeUI": "https://idmsa.apple.com/appleauth/auth/authorize/signin?client_id="
|
||||
+ WIDGET_KEY,
|
||||
"vettingUrlForEmail": "https://id.apple.com/IDMSEmailVetting/vetShareEmail",
|
||||
"accountCreate": "https://setup.icloud.com/setup/ws/1/createLiteAccount",
|
||||
"getICloudTerms": "https://setup.icloud.com/setup/ws/1/getTerms",
|
||||
"vettingUrlForPhone": "https://id.apple.com/IDMSEmailVetting/vetSharePhone",
|
||||
},
|
||||
"accountCreateEnabled": "true",
|
||||
},
|
||||
"hsaTrustedBrowser": False,
|
||||
"appsOrder": [
|
||||
"mail",
|
||||
"contacts",
|
||||
"calendar",
|
||||
"photos",
|
||||
"iclouddrive",
|
||||
"notes3",
|
||||
"reminders",
|
||||
"pages",
|
||||
"numbers",
|
||||
"keynote",
|
||||
"newspublisher",
|
||||
"fmf",
|
||||
"find",
|
||||
"settings",
|
||||
],
|
||||
"version": 2,
|
||||
"isExtendedLogin": False,
|
||||
"pcsServiceIdentitiesIncluded": False,
|
||||
"hsaChallengeRequired": True,
|
||||
"requestInfo": {"country": "FR", "timeZone": "GMT+1", "region": "IDF"},
|
||||
"pcsDeleted": False,
|
||||
"iCloudInfo": {"SafariBookmarksHasMigratedToCloudKit": True},
|
||||
"apps": {
|
||||
"calendar": {},
|
||||
"reminders": {},
|
||||
"keynote": {"isQualifiedForBeta": True},
|
||||
"settings": {"canLaunchWithOneFactor": True},
|
||||
"mail": {},
|
||||
"numbers": {"isQualifiedForBeta": True},
|
||||
"photos": {},
|
||||
"pages": {"isQualifiedForBeta": True},
|
||||
"notes3": {},
|
||||
"find": {"canLaunchWithOneFactor": True},
|
||||
"iclouddrive": {},
|
||||
"newspublisher": {"isHidden": True},
|
||||
"fmf": {},
|
||||
"contacts": {},
|
||||
},
|
||||
}
|
||||
|
||||
TRUSTED_DEVICE_1 = {
|
||||
"deviceType": "SMS",
|
||||
"areaCode": "",
|
||||
"phoneNumber": "*******58",
|
||||
"deviceId": "1",
|
||||
}
|
||||
TRUSTED_DEVICES = {"devices": [TRUSTED_DEVICE_1]}
|
||||
|
||||
VERIFICATION_CODE_OK = {"success": True}
|
||||
VERIFICATION_CODE_KO = {"success": False}
|
33
tests/test_account.py
Normal file
33
tests/test_account.py
Normal file
|
@ -0,0 +1,33 @@
|
|||
"""Account service tests."""
|
||||
from unittest import TestCase
|
||||
from . import PyiCloudServiceMock
|
||||
from .const import AUTHENTICATED_USER, VALID_PASSWORD
|
||||
|
||||
|
||||
class AccountServiceTest(TestCase):
|
||||
""""Account service tests"""
|
||||
|
||||
service = None
|
||||
|
||||
def setUp(self):
|
||||
self.service = PyiCloudServiceMock(AUTHENTICATED_USER, VALID_PASSWORD).account
|
||||
|
||||
def test_devices(self):
|
||||
"""Tests devices."""
|
||||
assert len(self.service.devices) == 2
|
||||
|
||||
for device in self.service.devices:
|
||||
assert device.name
|
||||
assert device.model
|
||||
assert device.udid
|
||||
assert device["serialNumber"]
|
||||
assert device["osVersion"]
|
||||
assert device["modelLargePhotoURL2x"]
|
||||
assert device["modelLargePhotoURL1x"]
|
||||
assert device["paymentMethods"]
|
||||
assert device["name"]
|
||||
assert device["model"]
|
||||
assert device["udid"]
|
||||
assert device["modelSmallPhotoURL2x"]
|
||||
assert device["modelSmallPhotoURL1x"]
|
||||
assert device["modelDisplayName"]
|
|
@ -1,6 +1,8 @@
|
|||
"""Cmdline tests."""
|
||||
from pyicloud import cmdline
|
||||
from . import PyiCloudServiceMock, AUTHENTICATED_USER, REQUIRES_2SA_USER, DEVICES
|
||||
from . import PyiCloudServiceMock
|
||||
from .const import AUTHENTICATED_USER, REQUIRES_2SA_USER, VALID_PASSWORD
|
||||
from .const_findmyiphone import FMI_FMLY_WORKING
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
@ -45,8 +47,11 @@ class TestCmdline(TestCase):
|
|||
with pytest.raises(SystemExit, match="2"):
|
||||
self.main(["--username"])
|
||||
|
||||
@patch("keyring.get_password", return_value=None)
|
||||
@patch("getpass.getpass")
|
||||
def test_username_password_invalid(self, mock_getpass):
|
||||
def test_username_password_invalid(
|
||||
self, mock_getpass, mock_get_password
|
||||
): # pylint: disable=unused-argument
|
||||
"""Test username and password commands."""
|
||||
# No password supplied
|
||||
mock_getpass.return_value = None
|
||||
|
@ -66,8 +71,11 @@ class TestCmdline(TestCase):
|
|||
):
|
||||
self.main(["--username", "invalid_user", "--password", "invalid_pass"])
|
||||
|
||||
@patch("keyring.get_password", return_value=None)
|
||||
@patch("pyicloud.cmdline.input")
|
||||
def test_username_password_requires_2sa(self, mock_input):
|
||||
def test_username_password_requires_2sa(
|
||||
self, mock_input, mock_get_password
|
||||
): # pylint: disable=unused-argument
|
||||
"""Test username and password commands."""
|
||||
# Valid connection for the first time
|
||||
mock_input.return_value = "0"
|
||||
|
@ -75,25 +83,29 @@ class TestCmdline(TestCase):
|
|||
# fmt: off
|
||||
self.main([
|
||||
'--username', REQUIRES_2SA_USER,
|
||||
'--password', 'valid_pass',
|
||||
'--password', VALID_PASSWORD,
|
||||
'--non-interactive',
|
||||
])
|
||||
# fmt: on
|
||||
|
||||
def test_device_outputfile(self):
|
||||
@patch("keyring.get_password", return_value=None)
|
||||
def test_device_outputfile(
|
||||
self, mock_get_password
|
||||
): # pylint: disable=unused-argument
|
||||
"""Test the outputfile command."""
|
||||
with pytest.raises(SystemExit, match="0"):
|
||||
# fmt: off
|
||||
self.main([
|
||||
'--username', AUTHENTICATED_USER,
|
||||
'--password', 'valid_pass',
|
||||
'--password', VALID_PASSWORD,
|
||||
'--non-interactive',
|
||||
'--outputfile'
|
||||
])
|
||||
# fmt: on
|
||||
|
||||
for key in DEVICES:
|
||||
file_name = DEVICES[key].content["name"].strip().lower() + ".fmip_snapshot"
|
||||
devices = FMI_FMLY_WORKING.get("content")
|
||||
for device in devices:
|
||||
file_name = device.get("name").strip().lower() + ".fmip_snapshot"
|
||||
|
||||
pickle_file = open(file_name, "rb")
|
||||
assert pickle_file
|
||||
|
@ -105,7 +117,7 @@ class TestCmdline(TestCase):
|
|||
contents.append(pickle.load(opened_file))
|
||||
except EOFError:
|
||||
break
|
||||
assert contents == [DEVICES[key].content]
|
||||
assert contents == [device]
|
||||
|
||||
pickle_file.close()
|
||||
os.remove(file_name)
|
||||
|
|
86
tests/test_findmyiphone.py
Normal file
86
tests/test_findmyiphone.py
Normal file
|
@ -0,0 +1,86 @@
|
|||
"""Find My iPhone service tests."""
|
||||
from unittest import TestCase
|
||||
from . import PyiCloudServiceMock
|
||||
from .const import AUTHENTICATED_USER, VALID_PASSWORD
|
||||
|
||||
|
||||
class FindMyiPhoneServiceTest(TestCase):
|
||||
""""Find My iPhone service tests"""
|
||||
|
||||
service = None
|
||||
|
||||
def setUp(self):
|
||||
self.service = PyiCloudServiceMock(AUTHENTICATED_USER, VALID_PASSWORD)
|
||||
|
||||
def test_devices(self):
|
||||
"""Tests devices."""
|
||||
assert len(list(self.service.devices)) == 13
|
||||
|
||||
for device in self.service.devices:
|
||||
assert device["canWipeAfterLock"] is not None
|
||||
assert device["baUUID"] is not None
|
||||
assert device["wipeInProgress"] is not None
|
||||
assert device["lostModeEnabled"] is not None
|
||||
assert device["activationLocked"] is not None
|
||||
assert device["passcodeLength"] is not None
|
||||
assert device["deviceStatus"] is not None
|
||||
assert device["features"] is not None
|
||||
assert device["lowPowerMode"] is not None
|
||||
assert device["rawDeviceModel"] is not None
|
||||
assert device["id"] is not None
|
||||
assert device["isLocating"] is not None
|
||||
assert device["modelDisplayName"] is not None
|
||||
assert device["lostTimestamp"] is not None
|
||||
assert device["batteryLevel"] is not None
|
||||
assert device["locationEnabled"] is not None
|
||||
assert device["locFoundEnabled"] is not None
|
||||
assert device["fmlyShare"] is not None
|
||||
assert device["lostModeCapable"] is not None
|
||||
assert device["wipedTimestamp"] is None
|
||||
assert device["deviceDisplayName"] is not None
|
||||
assert device["audioChannels"] is not None
|
||||
assert device["locationCapable"] is not None
|
||||
assert device["batteryStatus"] is not None
|
||||
assert device["trackingInfo"] is None
|
||||
assert device["name"] is not None
|
||||
assert device["isMac"] is not None
|
||||
assert device["thisDevice"] is not None
|
||||
assert device["deviceClass"] is not None
|
||||
assert device["deviceModel"] is not None
|
||||
assert device["maxMsgChar"] is not None
|
||||
assert device["darkWake"] is not None
|
||||
assert device["remoteWipe"] is None
|
||||
|
||||
assert device.data["canWipeAfterLock"] is not None
|
||||
assert device.data["baUUID"] is not None
|
||||
assert device.data["wipeInProgress"] is not None
|
||||
assert device.data["lostModeEnabled"] is not None
|
||||
assert device.data["activationLocked"] is not None
|
||||
assert device.data["passcodeLength"] is not None
|
||||
assert device.data["deviceStatus"] is not None
|
||||
assert device.data["features"] is not None
|
||||
assert device.data["lowPowerMode"] is not None
|
||||
assert device.data["rawDeviceModel"] is not None
|
||||
assert device.data["id"] is not None
|
||||
assert device.data["isLocating"] is not None
|
||||
assert device.data["modelDisplayName"] is not None
|
||||
assert device.data["lostTimestamp"] is not None
|
||||
assert device.data["batteryLevel"] is not None
|
||||
assert device.data["locationEnabled"] is not None
|
||||
assert device.data["locFoundEnabled"] is not None
|
||||
assert device.data["fmlyShare"] is not None
|
||||
assert device.data["lostModeCapable"] is not None
|
||||
assert device.data["wipedTimestamp"] is None
|
||||
assert device.data["deviceDisplayName"] is not None
|
||||
assert device.data["audioChannels"] is not None
|
||||
assert device.data["locationCapable"] is not None
|
||||
assert device.data["batteryStatus"] is not None
|
||||
assert device.data["trackingInfo"] is None
|
||||
assert device.data["name"] is not None
|
||||
assert device.data["isMac"] is not None
|
||||
assert device.data["thisDevice"] is not None
|
||||
assert device.data["deviceClass"] is not None
|
||||
assert device.data["deviceModel"] is not None
|
||||
assert device.data["maxMsgChar"] is not None
|
||||
assert device.data["darkWake"] is not None
|
||||
assert device.data["remoteWipe"] is None
|
Loading…
Reference in a new issue