Fix source code using Windows newline (#12248)

* 🚜 Fix usage of carriage return

* 🤝 Rebase and repeat

* 🚜 Fix file permissions
This commit is contained in:
Otto Winter 2018-02-09 08:11:47 +01:00 committed by Fabian Affolter
parent e4874fd7c7
commit 2ae0c5653e
14 changed files with 2730 additions and 2730 deletions

188
homeassistant/components/binary_sensor/mercedesme.py Executable file → Normal file
View File

@ -1,94 +1,94 @@
""" """
Support for Mercedes cars with Mercedes ME. Support for Mercedes cars with Mercedes ME.
For more details about this component, please refer to the documentation at For more details about this component, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.mercedesme/ https://home-assistant.io/components/binary_sensor.mercedesme/
""" """
import logging import logging
import datetime import datetime
from homeassistant.components.binary_sensor import (BinarySensorDevice) from homeassistant.components.binary_sensor import (BinarySensorDevice)
from homeassistant.components.mercedesme import ( from homeassistant.components.mercedesme import (
DATA_MME, MercedesMeEntity, BINARY_SENSORS) DATA_MME, MercedesMeEntity, BINARY_SENSORS)
DEPENDENCIES = ['mercedesme'] DEPENDENCIES = ['mercedesme']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
def setup_platform(hass, config, add_devices, discovery_info=None): def setup_platform(hass, config, add_devices, discovery_info=None):
"""Setup the sensor platform.""" """Setup the sensor platform."""
data = hass.data[DATA_MME].data data = hass.data[DATA_MME].data
if not data.cars: if not data.cars:
_LOGGER.error("No cars found. Check component log.") _LOGGER.error("No cars found. Check component log.")
return return
devices = [] devices = []
for car in data.cars: for car in data.cars:
for key, value in sorted(BINARY_SENSORS.items()): for key, value in sorted(BINARY_SENSORS.items()):
devices.append(MercedesMEBinarySensor( devices.append(MercedesMEBinarySensor(
data, key, value[0], car["vin"], None)) data, key, value[0], car["vin"], None))
add_devices(devices, True) add_devices(devices, True)
class MercedesMEBinarySensor(MercedesMeEntity, BinarySensorDevice): class MercedesMEBinarySensor(MercedesMeEntity, BinarySensorDevice):
"""Representation of a Sensor.""" """Representation of a Sensor."""
@property @property
def is_on(self): def is_on(self):
"""Return the state of the binary sensor.""" """Return the state of the binary sensor."""
return self._state return self._state
@property @property
def device_state_attributes(self): def device_state_attributes(self):
"""Return the state attributes.""" """Return the state attributes."""
if self._internal_name == "windowsClosed": if self._internal_name == "windowsClosed":
return { return {
"window_front_left": self._car["windowStatusFrontLeft"], "window_front_left": self._car["windowStatusFrontLeft"],
"window_front_right": self._car["windowStatusFrontRight"], "window_front_right": self._car["windowStatusFrontRight"],
"window_rear_left": self._car["windowStatusRearLeft"], "window_rear_left": self._car["windowStatusRearLeft"],
"window_rear_right": self._car["windowStatusRearRight"], "window_rear_right": self._car["windowStatusRearRight"],
"original_value": self._car[self._internal_name], "original_value": self._car[self._internal_name],
"last_update": datetime.datetime.fromtimestamp( "last_update": datetime.datetime.fromtimestamp(
self._car["lastUpdate"]).strftime('%Y-%m-%d %H:%M:%S'), self._car["lastUpdate"]).strftime('%Y-%m-%d %H:%M:%S'),
"car": self._car["license"] "car": self._car["license"]
} }
elif self._internal_name == "tireWarningLight": elif self._internal_name == "tireWarningLight":
return { return {
"front_right_tire_pressure_kpa": "front_right_tire_pressure_kpa":
self._car["frontRightTirePressureKpa"], self._car["frontRightTirePressureKpa"],
"front_left_tire_pressure_kpa": "front_left_tire_pressure_kpa":
self._car["frontLeftTirePressureKpa"], self._car["frontLeftTirePressureKpa"],
"rear_right_tire_pressure_kpa": "rear_right_tire_pressure_kpa":
self._car["rearRightTirePressureKpa"], self._car["rearRightTirePressureKpa"],
"rear_left_tire_pressure_kpa": "rear_left_tire_pressure_kpa":
self._car["rearLeftTirePressureKpa"], self._car["rearLeftTirePressureKpa"],
"original_value": self._car[self._internal_name], "original_value": self._car[self._internal_name],
"last_update": datetime.datetime.fromtimestamp( "last_update": datetime.datetime.fromtimestamp(
self._car["lastUpdate"] self._car["lastUpdate"]
).strftime('%Y-%m-%d %H:%M:%S'), ).strftime('%Y-%m-%d %H:%M:%S'),
"car": self._car["license"], "car": self._car["license"],
} }
return { return {
"original_value": self._car[self._internal_name], "original_value": self._car[self._internal_name],
"last_update": datetime.datetime.fromtimestamp( "last_update": datetime.datetime.fromtimestamp(
self._car["lastUpdate"]).strftime('%Y-%m-%d %H:%M:%S'), self._car["lastUpdate"]).strftime('%Y-%m-%d %H:%M:%S'),
"car": self._car["license"] "car": self._car["license"]
} }
def update(self): def update(self):
"""Fetch new state data for the sensor.""" """Fetch new state data for the sensor."""
self._car = next( self._car = next(
car for car in self._data.cars if car["vin"] == self._vin) car for car in self._data.cars if car["vin"] == self._vin)
if self._internal_name == "windowsClosed": if self._internal_name == "windowsClosed":
self._state = bool(self._car[self._internal_name] == "CLOSED") self._state = bool(self._car[self._internal_name] == "CLOSED")
elif self._internal_name == "tireWarningLight": elif self._internal_name == "tireWarningLight":
self._state = bool(self._car[self._internal_name] != "INACTIVE") self._state = bool(self._car[self._internal_name] != "INACTIVE")
else: else:
self._state = self._car[self._internal_name] is True self._state = self._car[self._internal_name] is True
_LOGGER.debug("Updated %s Value: %s IsOn: %s", _LOGGER.debug("Updated %s Value: %s IsOn: %s",
self._internal_name, self._state, self.is_on) self._internal_name, self._state, self.is_on)

0
homeassistant/components/camera/xeoma.py Executable file → Normal file
View File

142
homeassistant/components/device_tracker/mercedesme.py Executable file → Normal file
View File

@ -1,71 +1,71 @@
""" """
Support for Mercedes cars with Mercedes ME. Support for Mercedes cars with Mercedes ME.
For more details about this component, please refer to the documentation at For more details about this component, please refer to the documentation at
https://home-assistant.io/components/device_tracker.mercedesme/ https://home-assistant.io/components/device_tracker.mercedesme/
""" """
import logging import logging
from datetime import timedelta from datetime import timedelta
from homeassistant.components.mercedesme import DATA_MME from homeassistant.components.mercedesme import DATA_MME
from homeassistant.helpers.event import track_time_interval from homeassistant.helpers.event import track_time_interval
from homeassistant.util import Throttle from homeassistant.util import Throttle
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['mercedesme'] DEPENDENCIES = ['mercedesme']
MIN_TIME_BETWEEN_SCANS = timedelta(seconds=30) MIN_TIME_BETWEEN_SCANS = timedelta(seconds=30)
def setup_scanner(hass, config, see, discovery_info=None): def setup_scanner(hass, config, see, discovery_info=None):
"""Set up the Mercedes ME tracker.""" """Set up the Mercedes ME tracker."""
if discovery_info is None: if discovery_info is None:
return False return False
data = hass.data[DATA_MME].data data = hass.data[DATA_MME].data
if not data.cars: if not data.cars:
return False return False
MercedesMEDeviceTracker(hass, config, see, data) MercedesMEDeviceTracker(hass, config, see, data)
return True return True
class MercedesMEDeviceTracker(object): class MercedesMEDeviceTracker(object):
"""A class representing a Mercedes ME device tracker.""" """A class representing a Mercedes ME device tracker."""
def __init__(self, hass, config, see, data): def __init__(self, hass, config, see, data):
"""Initialize the Mercedes ME device tracker.""" """Initialize the Mercedes ME device tracker."""
self.see = see self.see = see
self.data = data self.data = data
self.update_info() self.update_info()
track_time_interval( track_time_interval(
hass, self.update_info, MIN_TIME_BETWEEN_SCANS) hass, self.update_info, MIN_TIME_BETWEEN_SCANS)
@Throttle(MIN_TIME_BETWEEN_SCANS) @Throttle(MIN_TIME_BETWEEN_SCANS)
def update_info(self, now=None): def update_info(self, now=None):
"""Update the device info.""" """Update the device info."""
for device in self.data.cars: for device in self.data.cars:
_LOGGER.debug("Updating %s", device["vin"]) _LOGGER.debug("Updating %s", device["vin"])
location = self.data.get_location(device["vin"]) location = self.data.get_location(device["vin"])
if location is None: if location is None:
return False return False
dev_id = device["vin"] dev_id = device["vin"]
name = device["license"] name = device["license"]
lat = location['positionLat']['value'] lat = location['positionLat']['value']
lon = location['positionLong']['value'] lon = location['positionLong']['value']
attrs = { attrs = {
'trackr_id': dev_id, 'trackr_id': dev_id,
'id': dev_id, 'id': dev_id,
'name': name 'name': name
} }
self.see( self.see(
dev_id=dev_id, host_name=name, dev_id=dev_id, host_name=name,
gps=(lat, lon), attributes=attrs gps=(lat, lon), attributes=attrs
) )
return True return True

308
homeassistant/components/mercedesme.py Executable file → Normal file
View File

@ -1,154 +1,154 @@
""" """
Support for MercedesME System. Support for MercedesME System.
For more details about this component, please refer to the documentation at For more details about this component, please refer to the documentation at
https://home-assistant.io/components/mercedesme/ https://home-assistant.io/components/mercedesme/
""" """
import asyncio import asyncio
import logging import logging
from datetime import timedelta from datetime import timedelta
import voluptuous as vol import voluptuous as vol
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.const import ( from homeassistant.const import (
CONF_USERNAME, CONF_PASSWORD, CONF_SCAN_INTERVAL, LENGTH_KILOMETERS) CONF_USERNAME, CONF_PASSWORD, CONF_SCAN_INTERVAL, LENGTH_KILOMETERS)
from homeassistant.helpers import discovery from homeassistant.helpers import discovery
from homeassistant.helpers.dispatcher import ( from homeassistant.helpers.dispatcher import (
async_dispatcher_connect, dispatcher_send) async_dispatcher_connect, dispatcher_send)
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from homeassistant.helpers.event import track_time_interval from homeassistant.helpers.event import track_time_interval
REQUIREMENTS = ['mercedesmejsonpy==0.1.2'] REQUIREMENTS = ['mercedesmejsonpy==0.1.2']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
BINARY_SENSORS = { BINARY_SENSORS = {
'doorsClosed': ['Doors closed'], 'doorsClosed': ['Doors closed'],
'windowsClosed': ['Windows closed'], 'windowsClosed': ['Windows closed'],
'locked': ['Doors locked'], 'locked': ['Doors locked'],
'tireWarningLight': ['Tire Warning'] 'tireWarningLight': ['Tire Warning']
} }
SENSORS = { SENSORS = {
'fuelLevelPercent': ['Fuel Level', '%'], 'fuelLevelPercent': ['Fuel Level', '%'],
'fuelRangeKm': ['Fuel Range', LENGTH_KILOMETERS], 'fuelRangeKm': ['Fuel Range', LENGTH_KILOMETERS],
'latestTrip': ['Latest Trip', None], 'latestTrip': ['Latest Trip', None],
'odometerKm': ['Odometer', LENGTH_KILOMETERS], 'odometerKm': ['Odometer', LENGTH_KILOMETERS],
'serviceIntervalDays': ['Next Service', 'days'] 'serviceIntervalDays': ['Next Service', 'days']
} }
DATA_MME = 'mercedesme' DATA_MME = 'mercedesme'
DOMAIN = 'mercedesme' DOMAIN = 'mercedesme'
NOTIFICATION_ID = 'mercedesme_integration_notification' NOTIFICATION_ID = 'mercedesme_integration_notification'
NOTIFICATION_TITLE = 'Mercedes me integration setup' NOTIFICATION_TITLE = 'Mercedes me integration setup'
SIGNAL_UPDATE_MERCEDESME = "mercedesme_update" SIGNAL_UPDATE_MERCEDESME = "mercedesme_update"
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({ DOMAIN: vol.Schema({
vol.Required(CONF_USERNAME): cv.string, vol.Required(CONF_USERNAME): cv.string,
vol.Required(CONF_PASSWORD): cv.string, vol.Required(CONF_PASSWORD): cv.string,
vol.Optional(CONF_SCAN_INTERVAL, default=30): vol.Optional(CONF_SCAN_INTERVAL, default=30):
vol.All(cv.positive_int, vol.Clamp(min=10)) vol.All(cv.positive_int, vol.Clamp(min=10))
}) })
}, extra=vol.ALLOW_EXTRA) }, extra=vol.ALLOW_EXTRA)
def setup(hass, config): def setup(hass, config):
"""Set up MercedesMe System.""" """Set up MercedesMe System."""
from mercedesmejsonpy.controller import Controller from mercedesmejsonpy.controller import Controller
from mercedesmejsonpy import Exceptions from mercedesmejsonpy import Exceptions
conf = config[DOMAIN] conf = config[DOMAIN]
username = conf.get(CONF_USERNAME) username = conf.get(CONF_USERNAME)
password = conf.get(CONF_PASSWORD) password = conf.get(CONF_PASSWORD)
scan_interval = conf.get(CONF_SCAN_INTERVAL) scan_interval = conf.get(CONF_SCAN_INTERVAL)
try: try:
mercedesme_api = Controller(username, password, scan_interval) mercedesme_api = Controller(username, password, scan_interval)
if not mercedesme_api.is_valid_session: if not mercedesme_api.is_valid_session:
raise Exceptions.MercedesMeException(500) raise Exceptions.MercedesMeException(500)
hass.data[DATA_MME] = MercedesMeHub(mercedesme_api) hass.data[DATA_MME] = MercedesMeHub(mercedesme_api)
except Exceptions.MercedesMeException as ex: except Exceptions.MercedesMeException as ex:
if ex.code == 401: if ex.code == 401:
hass.components.persistent_notification.create( hass.components.persistent_notification.create(
"Error:<br />Please check username and password." "Error:<br />Please check username and password."
"You will need to restart Home Assistant after fixing.", "You will need to restart Home Assistant after fixing.",
title=NOTIFICATION_TITLE, title=NOTIFICATION_TITLE,
notification_id=NOTIFICATION_ID) notification_id=NOTIFICATION_ID)
else: else:
hass.components.persistent_notification.create( hass.components.persistent_notification.create(
"Error:<br />Can't communicate with Mercedes me API.<br />" "Error:<br />Can't communicate with Mercedes me API.<br />"
"Error code: {} Reason: {}" "Error code: {} Reason: {}"
"You will need to restart Home Assistant after fixing." "You will need to restart Home Assistant after fixing."
"".format(ex.code, ex.message), "".format(ex.code, ex.message),
title=NOTIFICATION_TITLE, title=NOTIFICATION_TITLE,
notification_id=NOTIFICATION_ID) notification_id=NOTIFICATION_ID)
_LOGGER.error("Unable to communicate with Mercedes me API: %s", _LOGGER.error("Unable to communicate with Mercedes me API: %s",
ex.message) ex.message)
return False return False
discovery.load_platform(hass, 'sensor', DOMAIN, {}, config) discovery.load_platform(hass, 'sensor', DOMAIN, {}, config)
discovery.load_platform(hass, 'device_tracker', DOMAIN, {}, config) discovery.load_platform(hass, 'device_tracker', DOMAIN, {}, config)
discovery.load_platform(hass, 'binary_sensor', DOMAIN, {}, config) discovery.load_platform(hass, 'binary_sensor', DOMAIN, {}, config)
def hub_refresh(event_time): def hub_refresh(event_time):
"""Call Mercedes me API to refresh information.""" """Call Mercedes me API to refresh information."""
_LOGGER.info("Updating Mercedes me component.") _LOGGER.info("Updating Mercedes me component.")
hass.data[DATA_MME].data.update() hass.data[DATA_MME].data.update()
dispatcher_send(hass, SIGNAL_UPDATE_MERCEDESME) dispatcher_send(hass, SIGNAL_UPDATE_MERCEDESME)
track_time_interval( track_time_interval(
hass, hass,
hub_refresh, hub_refresh,
timedelta(seconds=scan_interval)) timedelta(seconds=scan_interval))
return True return True
class MercedesMeHub(object): class MercedesMeHub(object):
"""Representation of a base MercedesMe device.""" """Representation of a base MercedesMe device."""
def __init__(self, data): def __init__(self, data):
"""Initialize the entity.""" """Initialize the entity."""
self.data = data self.data = data
class MercedesMeEntity(Entity): class MercedesMeEntity(Entity):
"""Entity class for MercedesMe devices.""" """Entity class for MercedesMe devices."""
def __init__(self, data, internal_name, sensor_name, vin, unit): def __init__(self, data, internal_name, sensor_name, vin, unit):
"""Initialize the MercedesMe entity.""" """Initialize the MercedesMe entity."""
self._car = None self._car = None
self._data = data self._data = data
self._state = False self._state = False
self._name = sensor_name self._name = sensor_name
self._internal_name = internal_name self._internal_name = internal_name
self._unit = unit self._unit = unit
self._vin = vin self._vin = vin
@property @property
def name(self): def name(self):
"""Return the name of the sensor.""" """Return the name of the sensor."""
return self._name return self._name
@asyncio.coroutine @asyncio.coroutine
def async_added_to_hass(self): def async_added_to_hass(self):
"""Register callbacks.""" """Register callbacks."""
async_dispatcher_connect( async_dispatcher_connect(
self.hass, SIGNAL_UPDATE_MERCEDESME, self._update_callback) self.hass, SIGNAL_UPDATE_MERCEDESME, self._update_callback)
def _update_callback(self): def _update_callback(self):
"""Callback update method.""" """Callback update method."""
# If the method is made a callback this should be changed # If the method is made a callback this should be changed
# to the async version. Check core.callback # to the async version. Check core.callback
self.schedule_update_ha_state(True) self.schedule_update_ha_state(True)
@property @property
def unit_of_measurement(self): def unit_of_measurement(self):
"""Return the unit of measurement.""" """Return the unit of measurement."""
return self._unit return self._unit

0
homeassistant/components/remote/xiaomi_miio.py Executable file → Normal file
View File

166
homeassistant/components/sensor/mercedesme.py Executable file → Normal file
View File

@ -1,83 +1,83 @@
""" """
Support for Mercedes cars with Mercedes ME. Support for Mercedes cars with Mercedes ME.
For more details about this component, please refer to the documentation at For more details about this component, please refer to the documentation at
https://home-assistant.io/components/sensor.mercedesme/ https://home-assistant.io/components/sensor.mercedesme/
""" """
import logging import logging
import datetime import datetime
from homeassistant.components.mercedesme import ( from homeassistant.components.mercedesme import (
DATA_MME, MercedesMeEntity, SENSORS) DATA_MME, MercedesMeEntity, SENSORS)
DEPENDENCIES = ['mercedesme'] DEPENDENCIES = ['mercedesme']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
def setup_platform(hass, config, add_devices, discovery_info=None): def setup_platform(hass, config, add_devices, discovery_info=None):
"""Setup the sensor platform.""" """Setup the sensor platform."""
if discovery_info is None: if discovery_info is None:
return return
data = hass.data[DATA_MME].data data = hass.data[DATA_MME].data
if not data.cars: if not data.cars:
return return
devices = [] devices = []
for car in data.cars: for car in data.cars:
for key, value in sorted(SENSORS.items()): for key, value in sorted(SENSORS.items()):
devices.append( devices.append(
MercedesMESensor(data, key, value[0], car["vin"], value[1])) MercedesMESensor(data, key, value[0], car["vin"], value[1]))
add_devices(devices, True) add_devices(devices, True)
class MercedesMESensor(MercedesMeEntity): class MercedesMESensor(MercedesMeEntity):
"""Representation of a Sensor.""" """Representation of a Sensor."""
@property @property
def state(self): def state(self):
"""Return the state of the sensor.""" """Return the state of the sensor."""
return self._state return self._state
def update(self): def update(self):
"""Get the latest data and updates the states.""" """Get the latest data and updates the states."""
_LOGGER.debug("Updating %s", self._internal_name) _LOGGER.debug("Updating %s", self._internal_name)
self._car = next( self._car = next(
car for car in self._data.cars if car["vin"] == self._vin) car for car in self._data.cars if car["vin"] == self._vin)
if self._internal_name == "latestTrip": if self._internal_name == "latestTrip":
self._state = self._car["latestTrip"]["id"] self._state = self._car["latestTrip"]["id"]
else: else:
self._state = self._car[self._internal_name] self._state = self._car[self._internal_name]
@property @property
def device_state_attributes(self): def device_state_attributes(self):
"""Return the state attributes.""" """Return the state attributes."""
if self._internal_name == "latestTrip": if self._internal_name == "latestTrip":
return { return {
"duration_seconds": "duration_seconds":
self._car["latestTrip"]["durationSeconds"], self._car["latestTrip"]["durationSeconds"],
"distance_traveled_km": "distance_traveled_km":
self._car["latestTrip"]["distanceTraveledKm"], self._car["latestTrip"]["distanceTraveledKm"],
"started_at": datetime.datetime.fromtimestamp( "started_at": datetime.datetime.fromtimestamp(
self._car["latestTrip"]["startedAt"] self._car["latestTrip"]["startedAt"]
).strftime('%Y-%m-%d %H:%M:%S'), ).strftime('%Y-%m-%d %H:%M:%S'),
"average_speed_km_per_hr": "average_speed_km_per_hr":
self._car["latestTrip"]["averageSpeedKmPerHr"], self._car["latestTrip"]["averageSpeedKmPerHr"],
"finished": self._car["latestTrip"]["finished"], "finished": self._car["latestTrip"]["finished"],
"last_update": datetime.datetime.fromtimestamp( "last_update": datetime.datetime.fromtimestamp(
self._car["lastUpdate"] self._car["lastUpdate"]
).strftime('%Y-%m-%d %H:%M:%S'), ).strftime('%Y-%m-%d %H:%M:%S'),
"car": self._car["license"] "car": self._car["license"]
} }
return { return {
"last_update": datetime.datetime.fromtimestamp( "last_update": datetime.datetime.fromtimestamp(
self._car["lastUpdate"]).strftime('%Y-%m-%d %H:%M:%S'), self._car["lastUpdate"]).strftime('%Y-%m-%d %H:%M:%S'),
"car": self._car["license"] "car": self._car["license"]
} }

View File

@ -1,423 +1,423 @@
"""The tests for the google calendar component.""" """The tests for the google calendar component."""
# pylint: disable=protected-access # pylint: disable=protected-access
import logging import logging
import unittest import unittest
from unittest.mock import patch from unittest.mock import patch
import pytest import pytest
import homeassistant.components.calendar as calendar_base import homeassistant.components.calendar as calendar_base
import homeassistant.components.calendar.google as calendar import homeassistant.components.calendar.google as calendar
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
from homeassistant.const import CONF_PLATFORM, STATE_OFF, STATE_ON from homeassistant.const import CONF_PLATFORM, STATE_OFF, STATE_ON
from homeassistant.helpers.template import DATE_STR_FORMAT from homeassistant.helpers.template import DATE_STR_FORMAT
from tests.common import get_test_home_assistant from tests.common import get_test_home_assistant
TEST_PLATFORM = {calendar_base.DOMAIN: {CONF_PLATFORM: 'test'}} TEST_PLATFORM = {calendar_base.DOMAIN: {CONF_PLATFORM: 'test'}}
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
class TestComponentsGoogleCalendar(unittest.TestCase): class TestComponentsGoogleCalendar(unittest.TestCase):
"""Test the Google calendar.""" """Test the Google calendar."""
hass = None # HomeAssistant hass = None # HomeAssistant
# pylint: disable=invalid-name # pylint: disable=invalid-name
def setUp(self): def setUp(self):
"""Setup things to be run when tests are started.""" """Setup things to be run when tests are started."""
self.hass = get_test_home_assistant() self.hass = get_test_home_assistant()
# Set our timezone to CST/Regina so we can check calculations # Set our timezone to CST/Regina so we can check calculations
# This keeps UTC-6 all year round # This keeps UTC-6 all year round
dt_util.set_default_time_zone(dt_util.get_time_zone('America/Regina')) dt_util.set_default_time_zone(dt_util.get_time_zone('America/Regina'))
# pylint: disable=invalid-name # pylint: disable=invalid-name
def tearDown(self): def tearDown(self):
"""Stop everything that was started.""" """Stop everything that was started."""
dt_util.set_default_time_zone(dt_util.get_time_zone('UTC')) dt_util.set_default_time_zone(dt_util.get_time_zone('UTC'))
self.hass.stop() self.hass.stop()
@patch('homeassistant.components.calendar.google.GoogleCalendarData') @patch('homeassistant.components.calendar.google.GoogleCalendarData')
def test_all_day_event(self, mock_next_event): def test_all_day_event(self, mock_next_event):
"""Test that we can create an event trigger on device.""" """Test that we can create an event trigger on device."""
week_from_today = dt_util.dt.date.today() \ week_from_today = dt_util.dt.date.today() \
+ dt_util.dt.timedelta(days=7) + dt_util.dt.timedelta(days=7)
event = { event = {
'summary': 'Test All Day Event', 'summary': 'Test All Day Event',
'start': { 'start': {
'date': week_from_today.isoformat() 'date': week_from_today.isoformat()
}, },
'end': { 'end': {
'date': (week_from_today + dt_util.dt.timedelta(days=1)) 'date': (week_from_today + dt_util.dt.timedelta(days=1))
.isoformat() .isoformat()
}, },
'location': 'Test Cases', 'location': 'Test Cases',
'description': 'We\'re just testing that all day events get setup ' 'description': 'We\'re just testing that all day events get setup '
'correctly', 'correctly',
'kind': 'calendar#event', 'kind': 'calendar#event',
'created': '2016-06-23T16:37:57.000Z', 'created': '2016-06-23T16:37:57.000Z',
'transparency': 'transparent', 'transparency': 'transparent',
'updated': '2016-06-24T01:57:21.045Z', 'updated': '2016-06-24T01:57:21.045Z',
'reminders': {'useDefault': True}, 'reminders': {'useDefault': True},
'organizer': { 'organizer': {
'email': 'uvrttabwegnui4gtia3vyqb@import.calendar.google.com', 'email': 'uvrttabwegnui4gtia3vyqb@import.calendar.google.com',
'displayName': 'Organizer Name', 'displayName': 'Organizer Name',
'self': True 'self': True
}, },
'sequence': 0, 'sequence': 0,
'creator': { 'creator': {
'email': 'uvrttabwegnui4gtia3vyqb@import.calendar.google.com', 'email': 'uvrttabwegnui4gtia3vyqb@import.calendar.google.com',
'displayName': 'Organizer Name', 'displayName': 'Organizer Name',
'self': True 'self': True
}, },
'id': '_c8rinwq863h45qnucyoi43ny8', 'id': '_c8rinwq863h45qnucyoi43ny8',
'etag': '"2933466882090000"', 'etag': '"2933466882090000"',
'htmlLink': 'https://www.google.com/calendar/event?eid=*******', 'htmlLink': 'https://www.google.com/calendar/event?eid=*******',
'iCalUID': 'cydrevtfuybguinhomj@google.com', 'iCalUID': 'cydrevtfuybguinhomj@google.com',
'status': 'confirmed' 'status': 'confirmed'
} }
mock_next_event.return_value.event = event mock_next_event.return_value.event = event
device_name = 'Test All Day' device_name = 'Test All Day'
cal = calendar.GoogleCalendarEventDevice(self.hass, None, cal = calendar.GoogleCalendarEventDevice(self.hass, None,
'', {'name': device_name}) '', {'name': device_name})
self.assertEqual(cal.name, device_name) self.assertEqual(cal.name, device_name)
self.assertEqual(cal.state, STATE_OFF) self.assertEqual(cal.state, STATE_OFF)
self.assertFalse(cal.offset_reached()) self.assertFalse(cal.offset_reached())
self.assertEqual(cal.device_state_attributes, { self.assertEqual(cal.device_state_attributes, {
'message': event['summary'], 'message': event['summary'],
'all_day': True, 'all_day': True,
'offset_reached': False, 'offset_reached': False,
'start_time': '{} 00:00:00'.format(event['start']['date']), 'start_time': '{} 00:00:00'.format(event['start']['date']),
'end_time': '{} 00:00:00'.format(event['end']['date']), 'end_time': '{} 00:00:00'.format(event['end']['date']),
'location': event['location'], 'location': event['location'],
'description': event['description'] 'description': event['description']
}) })
@patch('homeassistant.components.calendar.google.GoogleCalendarData') @patch('homeassistant.components.calendar.google.GoogleCalendarData')
def test_future_event(self, mock_next_event): def test_future_event(self, mock_next_event):
"""Test that we can create an event trigger on device.""" """Test that we can create an event trigger on device."""
one_hour_from_now = dt_util.now() \ one_hour_from_now = dt_util.now() \
+ dt_util.dt.timedelta(minutes=30) + dt_util.dt.timedelta(minutes=30)
event = { event = {
'start': { 'start': {
'dateTime': one_hour_from_now.isoformat() 'dateTime': one_hour_from_now.isoformat()
}, },
'end': { 'end': {
'dateTime': (one_hour_from_now 'dateTime': (one_hour_from_now
+ dt_util.dt.timedelta(minutes=60)) + dt_util.dt.timedelta(minutes=60))
.isoformat() .isoformat()
}, },
'summary': 'Test Event in 30 minutes', 'summary': 'Test Event in 30 minutes',
'reminders': {'useDefault': True}, 'reminders': {'useDefault': True},
'id': 'aioehgni435lihje', 'id': 'aioehgni435lihje',
'status': 'confirmed', 'status': 'confirmed',
'updated': '2016-11-05T15:52:07.329Z', 'updated': '2016-11-05T15:52:07.329Z',
'organizer': { 'organizer': {
'email': 'uvrttabwegnui4gtia3vyqb@import.calendar.google.com', 'email': 'uvrttabwegnui4gtia3vyqb@import.calendar.google.com',
'displayName': 'Organizer Name', 'displayName': 'Organizer Name',
'self': True, 'self': True,
}, },
'created': '2016-11-05T15:52:07.000Z', 'created': '2016-11-05T15:52:07.000Z',
'iCalUID': 'dsfohuygtfvgbhnuju@google.com', 'iCalUID': 'dsfohuygtfvgbhnuju@google.com',
'sequence': 0, 'sequence': 0,
'creator': { 'creator': {
'email': 'uvrttabwegnui4gtia3vyqb@import.calendar.google.com', 'email': 'uvrttabwegnui4gtia3vyqb@import.calendar.google.com',
'displayName': 'Organizer Name', 'displayName': 'Organizer Name',
}, },
'etag': '"2956722254658000"', 'etag': '"2956722254658000"',
'kind': 'calendar#event', 'kind': 'calendar#event',
'htmlLink': 'https://www.google.com/calendar/event?eid=*******', 'htmlLink': 'https://www.google.com/calendar/event?eid=*******',
} }
mock_next_event.return_value.event = event mock_next_event.return_value.event = event
device_name = 'Test Future Event' device_name = 'Test Future Event'
device_id = 'test_future_event' device_id = 'test_future_event'
cal = calendar.GoogleCalendarEventDevice(self.hass, None, device_id, cal = calendar.GoogleCalendarEventDevice(self.hass, None, device_id,
{'name': device_name}) {'name': device_name})
self.assertEqual(cal.name, device_name) self.assertEqual(cal.name, device_name)
self.assertEqual(cal.state, STATE_OFF) self.assertEqual(cal.state, STATE_OFF)
self.assertFalse(cal.offset_reached()) self.assertFalse(cal.offset_reached())
self.assertEqual(cal.device_state_attributes, { self.assertEqual(cal.device_state_attributes, {
'message': event['summary'], 'message': event['summary'],
'all_day': False, 'all_day': False,
'offset_reached': False, 'offset_reached': False,
'start_time': one_hour_from_now.strftime(DATE_STR_FORMAT), 'start_time': one_hour_from_now.strftime(DATE_STR_FORMAT),
'end_time': 'end_time':
(one_hour_from_now + dt_util.dt.timedelta(minutes=60)) (one_hour_from_now + dt_util.dt.timedelta(minutes=60))
.strftime(DATE_STR_FORMAT), .strftime(DATE_STR_FORMAT),
'location': '', 'location': '',
'description': '' 'description': ''
}) })
@patch('homeassistant.components.calendar.google.GoogleCalendarData') @patch('homeassistant.components.calendar.google.GoogleCalendarData')
def test_in_progress_event(self, mock_next_event): def test_in_progress_event(self, mock_next_event):
"""Test that we can create an event trigger on device.""" """Test that we can create an event trigger on device."""
middle_of_event = dt_util.now() \ middle_of_event = dt_util.now() \
- dt_util.dt.timedelta(minutes=30) - dt_util.dt.timedelta(minutes=30)
event = { event = {
'start': { 'start': {
'dateTime': middle_of_event.isoformat() 'dateTime': middle_of_event.isoformat()
}, },
'end': { 'end': {
'dateTime': (middle_of_event + dt_util.dt 'dateTime': (middle_of_event + dt_util.dt
.timedelta(minutes=60)) .timedelta(minutes=60))
.isoformat() .isoformat()
}, },
'summary': 'Test Event in Progress', 'summary': 'Test Event in Progress',
'reminders': {'useDefault': True}, 'reminders': {'useDefault': True},
'id': 'aioehgni435lihje', 'id': 'aioehgni435lihje',
'status': 'confirmed', 'status': 'confirmed',
'updated': '2016-11-05T15:52:07.329Z', 'updated': '2016-11-05T15:52:07.329Z',
'organizer': { 'organizer': {
'email': 'uvrttabwegnui4gtia3vyqb@import.calendar.google.com', 'email': 'uvrttabwegnui4gtia3vyqb@import.calendar.google.com',
'displayName': 'Organizer Name', 'displayName': 'Organizer Name',
'self': True, 'self': True,
}, },
'created': '2016-11-05T15:52:07.000Z', 'created': '2016-11-05T15:52:07.000Z',
'iCalUID': 'dsfohuygtfvgbhnuju@google.com', 'iCalUID': 'dsfohuygtfvgbhnuju@google.com',
'sequence': 0, 'sequence': 0,
'creator': { 'creator': {
'email': 'uvrttabwegnui4gtia3vyqb@import.calendar.google.com', 'email': 'uvrttabwegnui4gtia3vyqb@import.calendar.google.com',
'displayName': 'Organizer Name', 'displayName': 'Organizer Name',
}, },
'etag': '"2956722254658000"', 'etag': '"2956722254658000"',
'kind': 'calendar#event', 'kind': 'calendar#event',
'htmlLink': 'https://www.google.com/calendar/event?eid=*******', 'htmlLink': 'https://www.google.com/calendar/event?eid=*******',
} }
mock_next_event.return_value.event = event mock_next_event.return_value.event = event
device_name = 'Test Event in Progress' device_name = 'Test Event in Progress'
device_id = 'test_event_in_progress' device_id = 'test_event_in_progress'
cal = calendar.GoogleCalendarEventDevice(self.hass, None, device_id, cal = calendar.GoogleCalendarEventDevice(self.hass, None, device_id,
{'name': device_name}) {'name': device_name})
self.assertEqual(cal.name, device_name) self.assertEqual(cal.name, device_name)
self.assertEqual(cal.state, STATE_ON) self.assertEqual(cal.state, STATE_ON)
self.assertFalse(cal.offset_reached()) self.assertFalse(cal.offset_reached())
self.assertEqual(cal.device_state_attributes, { self.assertEqual(cal.device_state_attributes, {
'message': event['summary'], 'message': event['summary'],
'all_day': False, 'all_day': False,
'offset_reached': False, 'offset_reached': False,
'start_time': middle_of_event.strftime(DATE_STR_FORMAT), 'start_time': middle_of_event.strftime(DATE_STR_FORMAT),
'end_time': 'end_time':
(middle_of_event + dt_util.dt.timedelta(minutes=60)) (middle_of_event + dt_util.dt.timedelta(minutes=60))
.strftime(DATE_STR_FORMAT), .strftime(DATE_STR_FORMAT),
'location': '', 'location': '',
'description': '' 'description': ''
}) })
@patch('homeassistant.components.calendar.google.GoogleCalendarData') @patch('homeassistant.components.calendar.google.GoogleCalendarData')
def test_offset_in_progress_event(self, mock_next_event): def test_offset_in_progress_event(self, mock_next_event):
"""Test that we can create an event trigger on device.""" """Test that we can create an event trigger on device."""
middle_of_event = dt_util.now() \ middle_of_event = dt_util.now() \
+ dt_util.dt.timedelta(minutes=14) + dt_util.dt.timedelta(minutes=14)
event_summary = 'Test Event in Progress' event_summary = 'Test Event in Progress'
event = { event = {
'start': { 'start': {
'dateTime': middle_of_event.isoformat() 'dateTime': middle_of_event.isoformat()
}, },
'end': { 'end': {
'dateTime': (middle_of_event + dt_util.dt 'dateTime': (middle_of_event + dt_util.dt
.timedelta(minutes=60)) .timedelta(minutes=60))
.isoformat() .isoformat()
}, },
'summary': '{} !!-15'.format(event_summary), 'summary': '{} !!-15'.format(event_summary),
'reminders': {'useDefault': True}, 'reminders': {'useDefault': True},
'id': 'aioehgni435lihje', 'id': 'aioehgni435lihje',
'status': 'confirmed', 'status': 'confirmed',
'updated': '2016-11-05T15:52:07.329Z', 'updated': '2016-11-05T15:52:07.329Z',
'organizer': { 'organizer': {
'email': 'uvrttabwegnui4gtia3vyqb@import.calendar.google.com', 'email': 'uvrttabwegnui4gtia3vyqb@import.calendar.google.com',
'displayName': 'Organizer Name', 'displayName': 'Organizer Name',
'self': True, 'self': True,
}, },
'created': '2016-11-05T15:52:07.000Z', 'created': '2016-11-05T15:52:07.000Z',
'iCalUID': 'dsfohuygtfvgbhnuju@google.com', 'iCalUID': 'dsfohuygtfvgbhnuju@google.com',
'sequence': 0, 'sequence': 0,
'creator': { 'creator': {
'email': 'uvrttabwegnui4gtia3vyqb@import.calendar.google.com', 'email': 'uvrttabwegnui4gtia3vyqb@import.calendar.google.com',
'displayName': 'Organizer Name', 'displayName': 'Organizer Name',
}, },
'etag': '"2956722254658000"', 'etag': '"2956722254658000"',
'kind': 'calendar#event', 'kind': 'calendar#event',
'htmlLink': 'https://www.google.com/calendar/event?eid=*******', 'htmlLink': 'https://www.google.com/calendar/event?eid=*******',
} }
mock_next_event.return_value.event = event mock_next_event.return_value.event = event
device_name = 'Test Event in Progress' device_name = 'Test Event in Progress'
device_id = 'test_event_in_progress' device_id = 'test_event_in_progress'
cal = calendar.GoogleCalendarEventDevice(self.hass, None, device_id, cal = calendar.GoogleCalendarEventDevice(self.hass, None, device_id,
{'name': device_name}) {'name': device_name})
self.assertEqual(cal.name, device_name) self.assertEqual(cal.name, device_name)
self.assertEqual(cal.state, STATE_OFF) self.assertEqual(cal.state, STATE_OFF)
self.assertTrue(cal.offset_reached()) self.assertTrue(cal.offset_reached())
self.assertEqual(cal.device_state_attributes, { self.assertEqual(cal.device_state_attributes, {
'message': event_summary, 'message': event_summary,
'all_day': False, 'all_day': False,
'offset_reached': True, 'offset_reached': True,
'start_time': middle_of_event.strftime(DATE_STR_FORMAT), 'start_time': middle_of_event.strftime(DATE_STR_FORMAT),
'end_time': 'end_time':
(middle_of_event + dt_util.dt.timedelta(minutes=60)) (middle_of_event + dt_util.dt.timedelta(minutes=60))
.strftime(DATE_STR_FORMAT), .strftime(DATE_STR_FORMAT),
'location': '', 'location': '',
'description': '' 'description': ''
}) })
@pytest.mark.skip @pytest.mark.skip
@patch('homeassistant.components.calendar.google.GoogleCalendarData') @patch('homeassistant.components.calendar.google.GoogleCalendarData')
def test_all_day_offset_in_progress_event(self, mock_next_event): def test_all_day_offset_in_progress_event(self, mock_next_event):
"""Test that we can create an event trigger on device.""" """Test that we can create an event trigger on device."""
tomorrow = dt_util.dt.date.today() \ tomorrow = dt_util.dt.date.today() \
+ dt_util.dt.timedelta(days=1) + dt_util.dt.timedelta(days=1)
event_summary = 'Test All Day Event Offset In Progress' event_summary = 'Test All Day Event Offset In Progress'
event = { event = {
'summary': '{} !!-25:0'.format(event_summary), 'summary': '{} !!-25:0'.format(event_summary),
'start': { 'start': {
'date': tomorrow.isoformat() 'date': tomorrow.isoformat()
}, },
'end': { 'end': {
'date': (tomorrow + dt_util.dt.timedelta(days=1)) 'date': (tomorrow + dt_util.dt.timedelta(days=1))
.isoformat() .isoformat()
}, },
'location': 'Test Cases', 'location': 'Test Cases',
'description': 'We\'re just testing that all day events get setup ' 'description': 'We\'re just testing that all day events get setup '
'correctly', 'correctly',
'kind': 'calendar#event', 'kind': 'calendar#event',
'created': '2016-06-23T16:37:57.000Z', 'created': '2016-06-23T16:37:57.000Z',
'transparency': 'transparent', 'transparency': 'transparent',
'updated': '2016-06-24T01:57:21.045Z', 'updated': '2016-06-24T01:57:21.045Z',
'reminders': {'useDefault': True}, 'reminders': {'useDefault': True},
'organizer': { 'organizer': {
'email': 'uvrttabwegnui4gtia3vyqb@import.calendar.google.com', 'email': 'uvrttabwegnui4gtia3vyqb@import.calendar.google.com',
'displayName': 'Organizer Name', 'displayName': 'Organizer Name',
'self': True 'self': True
}, },
'sequence': 0, 'sequence': 0,
'creator': { 'creator': {
'email': 'uvrttabwegnui4gtia3vyqb@import.calendar.google.com', 'email': 'uvrttabwegnui4gtia3vyqb@import.calendar.google.com',
'displayName': 'Organizer Name', 'displayName': 'Organizer Name',
'self': True 'self': True
}, },
'id': '_c8rinwq863h45qnucyoi43ny8', 'id': '_c8rinwq863h45qnucyoi43ny8',
'etag': '"2933466882090000"', 'etag': '"2933466882090000"',
'htmlLink': 'https://www.google.com/calendar/event?eid=*******', 'htmlLink': 'https://www.google.com/calendar/event?eid=*******',
'iCalUID': 'cydrevtfuybguinhomj@google.com', 'iCalUID': 'cydrevtfuybguinhomj@google.com',
'status': 'confirmed' 'status': 'confirmed'
} }
mock_next_event.return_value.event = event mock_next_event.return_value.event = event
device_name = 'Test All Day Offset In Progress' device_name = 'Test All Day Offset In Progress'
device_id = 'test_all_day_offset_in_progress' device_id = 'test_all_day_offset_in_progress'
cal = calendar.GoogleCalendarEventDevice(self.hass, None, device_id, cal = calendar.GoogleCalendarEventDevice(self.hass, None, device_id,
{'name': device_name}) {'name': device_name})
self.assertEqual(cal.name, device_name) self.assertEqual(cal.name, device_name)
self.assertEqual(cal.state, STATE_OFF) self.assertEqual(cal.state, STATE_OFF)
self.assertTrue(cal.offset_reached()) self.assertTrue(cal.offset_reached())
self.assertEqual(cal.device_state_attributes, { self.assertEqual(cal.device_state_attributes, {
'message': event_summary, 'message': event_summary,
'all_day': True, 'all_day': True,
'offset_reached': True, 'offset_reached': True,
'start_time': '{} 06:00:00'.format(event['start']['date']), 'start_time': '{} 06:00:00'.format(event['start']['date']),
'end_time': '{} 06:00:00'.format(event['end']['date']), 'end_time': '{} 06:00:00'.format(event['end']['date']),
'location': event['location'], 'location': event['location'],
'description': event['description'] 'description': event['description']
}) })
@patch('homeassistant.components.calendar.google.GoogleCalendarData') @patch('homeassistant.components.calendar.google.GoogleCalendarData')
def test_all_day_offset_event(self, mock_next_event): def test_all_day_offset_event(self, mock_next_event):
"""Test that we can create an event trigger on device.""" """Test that we can create an event trigger on device."""
tomorrow = dt_util.dt.date.today() \ tomorrow = dt_util.dt.date.today() \
+ dt_util.dt.timedelta(days=2) + dt_util.dt.timedelta(days=2)
offset_hours = (1 + dt_util.now().hour) offset_hours = (1 + dt_util.now().hour)
event_summary = 'Test All Day Event Offset' event_summary = 'Test All Day Event Offset'
event = { event = {
'summary': '{} !!-{}:0'.format(event_summary, offset_hours), 'summary': '{} !!-{}:0'.format(event_summary, offset_hours),
'start': { 'start': {
'date': tomorrow.isoformat() 'date': tomorrow.isoformat()
}, },
'end': { 'end': {
'date': (tomorrow + dt_util.dt.timedelta(days=1)) 'date': (tomorrow + dt_util.dt.timedelta(days=1))
.isoformat() .isoformat()
}, },
'location': 'Test Cases', 'location': 'Test Cases',
'description': 'We\'re just testing that all day events get setup ' 'description': 'We\'re just testing that all day events get setup '
'correctly', 'correctly',
'kind': 'calendar#event', 'kind': 'calendar#event',
'created': '2016-06-23T16:37:57.000Z', 'created': '2016-06-23T16:37:57.000Z',
'transparency': 'transparent', 'transparency': 'transparent',
'updated': '2016-06-24T01:57:21.045Z', 'updated': '2016-06-24T01:57:21.045Z',
'reminders': {'useDefault': True}, 'reminders': {'useDefault': True},
'organizer': { 'organizer': {
'email': 'uvrttabwegnui4gtia3vyqb@import.calendar.google.com', 'email': 'uvrttabwegnui4gtia3vyqb@import.calendar.google.com',
'displayName': 'Organizer Name', 'displayName': 'Organizer Name',
'self': True 'self': True
}, },
'sequence': 0, 'sequence': 0,
'creator': { 'creator': {
'email': 'uvrttabwegnui4gtia3vyqb@import.calendar.google.com', 'email': 'uvrttabwegnui4gtia3vyqb@import.calendar.google.com',
'displayName': 'Organizer Name', 'displayName': 'Organizer Name',
'self': True 'self': True
}, },
'id': '_c8rinwq863h45qnucyoi43ny8', 'id': '_c8rinwq863h45qnucyoi43ny8',
'etag': '"2933466882090000"', 'etag': '"2933466882090000"',
'htmlLink': 'https://www.google.com/calendar/event?eid=*******', 'htmlLink': 'https://www.google.com/calendar/event?eid=*******',
'iCalUID': 'cydrevtfuybguinhomj@google.com', 'iCalUID': 'cydrevtfuybguinhomj@google.com',
'status': 'confirmed' 'status': 'confirmed'
} }
mock_next_event.return_value.event = event mock_next_event.return_value.event = event
device_name = 'Test All Day Offset' device_name = 'Test All Day Offset'
device_id = 'test_all_day_offset' device_id = 'test_all_day_offset'
cal = calendar.GoogleCalendarEventDevice(self.hass, None, device_id, cal = calendar.GoogleCalendarEventDevice(self.hass, None, device_id,
{'name': device_name}) {'name': device_name})
self.assertEqual(cal.name, device_name) self.assertEqual(cal.name, device_name)
self.assertEqual(cal.state, STATE_OFF) self.assertEqual(cal.state, STATE_OFF)
self.assertFalse(cal.offset_reached()) self.assertFalse(cal.offset_reached())
self.assertEqual(cal.device_state_attributes, { self.assertEqual(cal.device_state_attributes, {
'message': event_summary, 'message': event_summary,
'all_day': True, 'all_day': True,
'offset_reached': False, 'offset_reached': False,
'start_time': '{} 00:00:00'.format(event['start']['date']), 'start_time': '{} 00:00:00'.format(event['start']['date']),
'end_time': '{} 00:00:00'.format(event['end']['date']), 'end_time': '{} 00:00:00'.format(event['end']['date']),
'location': event['location'], 'location': event['location'],
'description': event['description'] 'description': event['description']
}) })

View File

@ -1 +1 @@
"""Tests for the cloud component.""" """Tests for the cloud component."""

View File

@ -1,265 +1,265 @@
"""The tests for the Xiaomi router device tracker platform.""" """The tests for the Xiaomi router device tracker platform."""
import logging import logging
import unittest import unittest
from unittest import mock from unittest import mock
from unittest.mock import patch from unittest.mock import patch
import requests import requests
from homeassistant.components.device_tracker import DOMAIN, xiaomi as xiaomi from homeassistant.components.device_tracker import DOMAIN, xiaomi as xiaomi
from homeassistant.components.device_tracker.xiaomi import get_scanner from homeassistant.components.device_tracker.xiaomi import get_scanner
from homeassistant.const import (CONF_HOST, CONF_USERNAME, CONF_PASSWORD, from homeassistant.const import (CONF_HOST, CONF_USERNAME, CONF_PASSWORD,
CONF_PLATFORM) CONF_PLATFORM)
from tests.common import get_test_home_assistant from tests.common import get_test_home_assistant
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
INVALID_USERNAME = 'bob' INVALID_USERNAME = 'bob'
TOKEN_TIMEOUT_USERNAME = 'tok' TOKEN_TIMEOUT_USERNAME = 'tok'
URL_AUTHORIZE = 'http://192.168.0.1/cgi-bin/luci/api/xqsystem/login' URL_AUTHORIZE = 'http://192.168.0.1/cgi-bin/luci/api/xqsystem/login'
URL_LIST_END = 'api/misystem/devicelist' URL_LIST_END = 'api/misystem/devicelist'
FIRST_CALL = True FIRST_CALL = True
def mocked_requests(*args, **kwargs): def mocked_requests(*args, **kwargs):
"""Mock requests.get invocations.""" """Mock requests.get invocations."""
class MockResponse: class MockResponse:
"""Class to represent a mocked response.""" """Class to represent a mocked response."""
def __init__(self, json_data, status_code): def __init__(self, json_data, status_code):
"""Initialize the mock response class.""" """Initialize the mock response class."""
self.json_data = json_data self.json_data = json_data
self.status_code = status_code self.status_code = status_code
def json(self): def json(self):
"""Return the json of the response.""" """Return the json of the response."""
return self.json_data return self.json_data
@property @property
def content(self): def content(self):
"""Return the content of the response.""" """Return the content of the response."""
return self.json() return self.json()
def raise_for_status(self): def raise_for_status(self):
"""Raise an HTTPError if status is not 200.""" """Raise an HTTPError if status is not 200."""
if self.status_code != 200: if self.status_code != 200:
raise requests.HTTPError(self.status_code) raise requests.HTTPError(self.status_code)
data = kwargs.get('data') data = kwargs.get('data')
global FIRST_CALL global FIRST_CALL
if data and data.get('username', None) == INVALID_USERNAME: if data and data.get('username', None) == INVALID_USERNAME:
# deliver an invalid token # deliver an invalid token
return MockResponse({ return MockResponse({
"code": "401", "code": "401",
"msg": "Invalid token" "msg": "Invalid token"
}, 200) }, 200)
elif data and data.get('username', None) == TOKEN_TIMEOUT_USERNAME: elif data and data.get('username', None) == TOKEN_TIMEOUT_USERNAME:
# deliver an expired token # deliver an expired token
return MockResponse({ return MockResponse({
"url": "/cgi-bin/luci/;stok=ef5860/web/home", "url": "/cgi-bin/luci/;stok=ef5860/web/home",
"token": "timedOut", "token": "timedOut",
"code": "0" "code": "0"
}, 200) }, 200)
elif str(args[0]).startswith(URL_AUTHORIZE): elif str(args[0]).startswith(URL_AUTHORIZE):
# deliver an authorized token # deliver an authorized token
return MockResponse({ return MockResponse({
"url": "/cgi-bin/luci/;stok=ef5860/web/home", "url": "/cgi-bin/luci/;stok=ef5860/web/home",
"token": "ef5860", "token": "ef5860",
"code": "0" "code": "0"
}, 200) }, 200)
elif str(args[0]).endswith("timedOut/" + URL_LIST_END) \ elif str(args[0]).endswith("timedOut/" + URL_LIST_END) \
and FIRST_CALL is True: and FIRST_CALL is True:
FIRST_CALL = False FIRST_CALL = False
# deliver an error when called with expired token # deliver an error when called with expired token
return MockResponse({ return MockResponse({
"code": "401", "code": "401",
"msg": "Invalid token" "msg": "Invalid token"
}, 200) }, 200)
elif str(args[0]).endswith(URL_LIST_END): elif str(args[0]).endswith(URL_LIST_END):
# deliver the device list # deliver the device list
return MockResponse({ return MockResponse({
"mac": "1C:98:EC:0E:D5:A4", "mac": "1C:98:EC:0E:D5:A4",
"list": [ "list": [
{ {
"mac": "23:83:BF:F6:38:A0", "mac": "23:83:BF:F6:38:A0",
"oname": "12255ff", "oname": "12255ff",
"isap": 0, "isap": 0,
"parent": "", "parent": "",
"authority": { "authority": {
"wan": 1, "wan": 1,
"pridisk": 0, "pridisk": 0,
"admin": 1, "admin": 1,
"lan": 0 "lan": 0
}, },
"push": 0, "push": 0,
"online": 1, "online": 1,
"name": "Device1", "name": "Device1",
"times": 0, "times": 0,
"ip": [ "ip": [
{ {
"downspeed": "0", "downspeed": "0",
"online": "496957", "online": "496957",
"active": 1, "active": 1,
"upspeed": "0", "upspeed": "0",
"ip": "192.168.0.25" "ip": "192.168.0.25"
} }
], ],
"statistics": { "statistics": {
"downspeed": "0", "downspeed": "0",
"online": "496957", "online": "496957",
"upspeed": "0" "upspeed": "0"
}, },
"icon": "", "icon": "",
"type": 1 "type": 1
}, },
{ {
"mac": "1D:98:EC:5E:D5:A6", "mac": "1D:98:EC:5E:D5:A6",
"oname": "CdddFG58", "oname": "CdddFG58",
"isap": 0, "isap": 0,
"parent": "", "parent": "",
"authority": { "authority": {
"wan": 1, "wan": 1,
"pridisk": 0, "pridisk": 0,
"admin": 1, "admin": 1,
"lan": 0 "lan": 0
}, },
"push": 0, "push": 0,
"online": 1, "online": 1,
"name": "Device2", "name": "Device2",
"times": 0, "times": 0,
"ip": [ "ip": [
{ {
"downspeed": "0", "downspeed": "0",
"online": "347325", "online": "347325",
"active": 1, "active": 1,
"upspeed": "0", "upspeed": "0",
"ip": "192.168.0.3" "ip": "192.168.0.3"
} }
], ],
"statistics": { "statistics": {
"downspeed": "0", "downspeed": "0",
"online": "347325", "online": "347325",
"upspeed": "0" "upspeed": "0"
}, },
"icon": "", "icon": "",
"type": 0 "type": 0
}, },
], ],
"code": 0 "code": 0
}, 200) }, 200)
else: else:
_LOGGER.debug('UNKNOWN ROUTE') _LOGGER.debug('UNKNOWN ROUTE')
class TestXiaomiDeviceScanner(unittest.TestCase): class TestXiaomiDeviceScanner(unittest.TestCase):
"""Xiaomi device scanner test class.""" """Xiaomi device scanner test class."""
def setUp(self): def setUp(self):
"""Initialize values for this testcase class.""" """Initialize values for this testcase class."""
self.hass = get_test_home_assistant() self.hass = get_test_home_assistant()
def tearDown(self): def tearDown(self):
"""Stop everything that was started.""" """Stop everything that was started."""
self.hass.stop() self.hass.stop()
@mock.patch( @mock.patch(
'homeassistant.components.device_tracker.xiaomi.XiaomiDeviceScanner', 'homeassistant.components.device_tracker.xiaomi.XiaomiDeviceScanner',
return_value=mock.MagicMock()) return_value=mock.MagicMock())
def test_config(self, xiaomi_mock): def test_config(self, xiaomi_mock):
"""Testing minimal configuration.""" """Testing minimal configuration."""
config = { config = {
DOMAIN: xiaomi.PLATFORM_SCHEMA({ DOMAIN: xiaomi.PLATFORM_SCHEMA({
CONF_PLATFORM: xiaomi.DOMAIN, CONF_PLATFORM: xiaomi.DOMAIN,
CONF_HOST: '192.168.0.1', CONF_HOST: '192.168.0.1',
CONF_PASSWORD: 'passwordTest' CONF_PASSWORD: 'passwordTest'
}) })
} }
xiaomi.get_scanner(self.hass, config) xiaomi.get_scanner(self.hass, config)
self.assertEqual(xiaomi_mock.call_count, 1) self.assertEqual(xiaomi_mock.call_count, 1)
self.assertEqual(xiaomi_mock.call_args, mock.call(config[DOMAIN])) self.assertEqual(xiaomi_mock.call_args, mock.call(config[DOMAIN]))
call_arg = xiaomi_mock.call_args[0][0] call_arg = xiaomi_mock.call_args[0][0]
self.assertEqual(call_arg['username'], 'admin') self.assertEqual(call_arg['username'], 'admin')
self.assertEqual(call_arg['password'], 'passwordTest') self.assertEqual(call_arg['password'], 'passwordTest')
self.assertEqual(call_arg['host'], '192.168.0.1') self.assertEqual(call_arg['host'], '192.168.0.1')
self.assertEqual(call_arg['platform'], 'device_tracker') self.assertEqual(call_arg['platform'], 'device_tracker')
@mock.patch( @mock.patch(
'homeassistant.components.device_tracker.xiaomi.XiaomiDeviceScanner', 'homeassistant.components.device_tracker.xiaomi.XiaomiDeviceScanner',
return_value=mock.MagicMock()) return_value=mock.MagicMock())
def test_config_full(self, xiaomi_mock): def test_config_full(self, xiaomi_mock):
"""Testing full configuration.""" """Testing full configuration."""
config = { config = {
DOMAIN: xiaomi.PLATFORM_SCHEMA({ DOMAIN: xiaomi.PLATFORM_SCHEMA({
CONF_PLATFORM: xiaomi.DOMAIN, CONF_PLATFORM: xiaomi.DOMAIN,
CONF_HOST: '192.168.0.1', CONF_HOST: '192.168.0.1',
CONF_USERNAME: 'alternativeAdminName', CONF_USERNAME: 'alternativeAdminName',
CONF_PASSWORD: 'passwordTest' CONF_PASSWORD: 'passwordTest'
}) })
} }
xiaomi.get_scanner(self.hass, config) xiaomi.get_scanner(self.hass, config)
self.assertEqual(xiaomi_mock.call_count, 1) self.assertEqual(xiaomi_mock.call_count, 1)
self.assertEqual(xiaomi_mock.call_args, mock.call(config[DOMAIN])) self.assertEqual(xiaomi_mock.call_args, mock.call(config[DOMAIN]))
call_arg = xiaomi_mock.call_args[0][0] call_arg = xiaomi_mock.call_args[0][0]
self.assertEqual(call_arg['username'], 'alternativeAdminName') self.assertEqual(call_arg['username'], 'alternativeAdminName')
self.assertEqual(call_arg['password'], 'passwordTest') self.assertEqual(call_arg['password'], 'passwordTest')
self.assertEqual(call_arg['host'], '192.168.0.1') self.assertEqual(call_arg['host'], '192.168.0.1')
self.assertEqual(call_arg['platform'], 'device_tracker') self.assertEqual(call_arg['platform'], 'device_tracker')
@patch('requests.get', side_effect=mocked_requests) @patch('requests.get', side_effect=mocked_requests)
@patch('requests.post', side_effect=mocked_requests) @patch('requests.post', side_effect=mocked_requests)
def test_invalid_credential(self, mock_get, mock_post): def test_invalid_credential(self, mock_get, mock_post):
""""Testing invalid credential handling.""" """"Testing invalid credential handling."""
config = { config = {
DOMAIN: xiaomi.PLATFORM_SCHEMA({ DOMAIN: xiaomi.PLATFORM_SCHEMA({
CONF_PLATFORM: xiaomi.DOMAIN, CONF_PLATFORM: xiaomi.DOMAIN,
CONF_HOST: '192.168.0.1', CONF_HOST: '192.168.0.1',
CONF_USERNAME: INVALID_USERNAME, CONF_USERNAME: INVALID_USERNAME,
CONF_PASSWORD: 'passwordTest' CONF_PASSWORD: 'passwordTest'
}) })
} }
self.assertIsNone(get_scanner(self.hass, config)) self.assertIsNone(get_scanner(self.hass, config))
@patch('requests.get', side_effect=mocked_requests) @patch('requests.get', side_effect=mocked_requests)
@patch('requests.post', side_effect=mocked_requests) @patch('requests.post', side_effect=mocked_requests)
def test_valid_credential(self, mock_get, mock_post): def test_valid_credential(self, mock_get, mock_post):
""""Testing valid refresh.""" """"Testing valid refresh."""
config = { config = {
DOMAIN: xiaomi.PLATFORM_SCHEMA({ DOMAIN: xiaomi.PLATFORM_SCHEMA({
CONF_PLATFORM: xiaomi.DOMAIN, CONF_PLATFORM: xiaomi.DOMAIN,
CONF_HOST: '192.168.0.1', CONF_HOST: '192.168.0.1',
CONF_USERNAME: 'admin', CONF_USERNAME: 'admin',
CONF_PASSWORD: 'passwordTest' CONF_PASSWORD: 'passwordTest'
}) })
} }
scanner = get_scanner(self.hass, config) scanner = get_scanner(self.hass, config)
self.assertIsNotNone(scanner) self.assertIsNotNone(scanner)
self.assertEqual(2, len(scanner.scan_devices())) self.assertEqual(2, len(scanner.scan_devices()))
self.assertEqual("Device1", self.assertEqual("Device1",
scanner.get_device_name("23:83:BF:F6:38:A0")) scanner.get_device_name("23:83:BF:F6:38:A0"))
self.assertEqual("Device2", self.assertEqual("Device2",
scanner.get_device_name("1D:98:EC:5E:D5:A6")) scanner.get_device_name("1D:98:EC:5E:D5:A6"))
@patch('requests.get', side_effect=mocked_requests) @patch('requests.get', side_effect=mocked_requests)
@patch('requests.post', side_effect=mocked_requests) @patch('requests.post', side_effect=mocked_requests)
def test_token_timed_out(self, mock_get, mock_post): def test_token_timed_out(self, mock_get, mock_post):
""""Testing refresh with a timed out token. """"Testing refresh with a timed out token.
New token is requested and list is downloaded a second time. New token is requested and list is downloaded a second time.
""" """
config = { config = {
DOMAIN: xiaomi.PLATFORM_SCHEMA({ DOMAIN: xiaomi.PLATFORM_SCHEMA({
CONF_PLATFORM: xiaomi.DOMAIN, CONF_PLATFORM: xiaomi.DOMAIN,
CONF_HOST: '192.168.0.1', CONF_HOST: '192.168.0.1',
CONF_USERNAME: TOKEN_TIMEOUT_USERNAME, CONF_USERNAME: TOKEN_TIMEOUT_USERNAME,
CONF_PASSWORD: 'passwordTest' CONF_PASSWORD: 'passwordTest'
}) })
} }
scanner = get_scanner(self.hass, config) scanner = get_scanner(self.hass, config)
self.assertIsNotNone(scanner) self.assertIsNotNone(scanner)
self.assertEqual(2, len(scanner.scan_devices())) self.assertEqual(2, len(scanner.scan_devices()))
self.assertEqual("Device1", self.assertEqual("Device1",
scanner.get_device_name("23:83:BF:F6:38:A0")) scanner.get_device_name("23:83:BF:F6:38:A0"))
self.assertEqual("Device2", self.assertEqual("Device2",
scanner.get_device_name("1D:98:EC:5E:D5:A6")) scanner.get_device_name("1D:98:EC:5E:D5:A6"))

View File

@ -1,128 +1,128 @@
"""Test the Emulated Hue component.""" """Test the Emulated Hue component."""
import json import json
from unittest.mock import patch, Mock, mock_open from unittest.mock import patch, Mock, mock_open
from homeassistant.components.emulated_hue import Config, _LOGGER from homeassistant.components.emulated_hue import Config, _LOGGER
def test_config_google_home_entity_id_to_number(): def test_config_google_home_entity_id_to_number():
"""Test config adheres to the type.""" """Test config adheres to the type."""
conf = Config(Mock(), { conf = Config(Mock(), {
'type': 'google_home' 'type': 'google_home'
}) })
mop = mock_open(read_data=json.dumps({'1': 'light.test2'})) mop = mock_open(read_data=json.dumps({'1': 'light.test2'}))
handle = mop() handle = mop()
with patch('homeassistant.util.json.open', mop, create=True): with patch('homeassistant.util.json.open', mop, create=True):
number = conf.entity_id_to_number('light.test') number = conf.entity_id_to_number('light.test')
assert number == '2' assert number == '2'
assert handle.write.call_count == 1 assert handle.write.call_count == 1
assert json.loads(handle.write.mock_calls[0][1][0]) == { assert json.loads(handle.write.mock_calls[0][1][0]) == {
'1': 'light.test2', '1': 'light.test2',
'2': 'light.test', '2': 'light.test',
} }
number = conf.entity_id_to_number('light.test') number = conf.entity_id_to_number('light.test')
assert number == '2' assert number == '2'
assert handle.write.call_count == 1 assert handle.write.call_count == 1
number = conf.entity_id_to_number('light.test2') number = conf.entity_id_to_number('light.test2')
assert number == '1' assert number == '1'
assert handle.write.call_count == 1 assert handle.write.call_count == 1
entity_id = conf.number_to_entity_id('1') entity_id = conf.number_to_entity_id('1')
assert entity_id == 'light.test2' assert entity_id == 'light.test2'
def test_config_google_home_entity_id_to_number_altered(): def test_config_google_home_entity_id_to_number_altered():
"""Test config adheres to the type.""" """Test config adheres to the type."""
conf = Config(Mock(), { conf = Config(Mock(), {
'type': 'google_home' 'type': 'google_home'
}) })
mop = mock_open(read_data=json.dumps({'21': 'light.test2'})) mop = mock_open(read_data=json.dumps({'21': 'light.test2'}))
handle = mop() handle = mop()
with patch('homeassistant.util.json.open', mop, create=True): with patch('homeassistant.util.json.open', mop, create=True):
number = conf.entity_id_to_number('light.test') number = conf.entity_id_to_number('light.test')
assert number == '22' assert number == '22'
assert handle.write.call_count == 1 assert handle.write.call_count == 1
assert json.loads(handle.write.mock_calls[0][1][0]) == { assert json.loads(handle.write.mock_calls[0][1][0]) == {
'21': 'light.test2', '21': 'light.test2',
'22': 'light.test', '22': 'light.test',
} }
number = conf.entity_id_to_number('light.test') number = conf.entity_id_to_number('light.test')
assert number == '22' assert number == '22'
assert handle.write.call_count == 1 assert handle.write.call_count == 1
number = conf.entity_id_to_number('light.test2') number = conf.entity_id_to_number('light.test2')
assert number == '21' assert number == '21'
assert handle.write.call_count == 1 assert handle.write.call_count == 1
entity_id = conf.number_to_entity_id('21') entity_id = conf.number_to_entity_id('21')
assert entity_id == 'light.test2' assert entity_id == 'light.test2'
def test_config_google_home_entity_id_to_number_empty(): def test_config_google_home_entity_id_to_number_empty():
"""Test config adheres to the type.""" """Test config adheres to the type."""
conf = Config(Mock(), { conf = Config(Mock(), {
'type': 'google_home' 'type': 'google_home'
}) })
mop = mock_open(read_data='') mop = mock_open(read_data='')
handle = mop() handle = mop()
with patch('homeassistant.util.json.open', mop, create=True): with patch('homeassistant.util.json.open', mop, create=True):
number = conf.entity_id_to_number('light.test') number = conf.entity_id_to_number('light.test')
assert number == '1' assert number == '1'
assert handle.write.call_count == 1 assert handle.write.call_count == 1
assert json.loads(handle.write.mock_calls[0][1][0]) == { assert json.loads(handle.write.mock_calls[0][1][0]) == {
'1': 'light.test', '1': 'light.test',
} }
number = conf.entity_id_to_number('light.test') number = conf.entity_id_to_number('light.test')
assert number == '1' assert number == '1'
assert handle.write.call_count == 1 assert handle.write.call_count == 1
number = conf.entity_id_to_number('light.test2') number = conf.entity_id_to_number('light.test2')
assert number == '2' assert number == '2'
assert handle.write.call_count == 2 assert handle.write.call_count == 2
entity_id = conf.number_to_entity_id('2') entity_id = conf.number_to_entity_id('2')
assert entity_id == 'light.test2' assert entity_id == 'light.test2'
def test_config_alexa_entity_id_to_number(): def test_config_alexa_entity_id_to_number():
"""Test config adheres to the type.""" """Test config adheres to the type."""
conf = Config(None, { conf = Config(None, {
'type': 'alexa' 'type': 'alexa'
}) })
number = conf.entity_id_to_number('light.test') number = conf.entity_id_to_number('light.test')
assert number == 'light.test' assert number == 'light.test'
number = conf.entity_id_to_number('light.test') number = conf.entity_id_to_number('light.test')
assert number == 'light.test' assert number == 'light.test'
number = conf.entity_id_to_number('light.test2') number = conf.entity_id_to_number('light.test2')
assert number == 'light.test2' assert number == 'light.test2'
entity_id = conf.number_to_entity_id('light.test') entity_id = conf.number_to_entity_id('light.test')
assert entity_id == 'light.test' assert entity_id == 'light.test'
def test_warning_config_google_home_listen_port(): def test_warning_config_google_home_listen_port():
"""Test we warn when non-default port is used for Google Home.""" """Test we warn when non-default port is used for Google Home."""
with patch.object(_LOGGER, 'warning') as mock_warn: with patch.object(_LOGGER, 'warning') as mock_warn:
Config(None, { Config(None, {
'type': 'google_home', 'type': 'google_home',
'host_ip': '123.123.123.123', 'host_ip': '123.123.123.123',
'listen_port': 8300 'listen_port': 8300
}) })
assert mock_warn.called assert mock_warn.called
assert mock_warn.mock_calls[0][1][0] == \ assert mock_warn.mock_calls[0][1][0] == \
"When targeting Google Home, listening port has to be port 80" "When targeting Google Home, listening port has to be port 80"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,216 +1,216 @@
"""The tests for the hddtemp platform.""" """The tests for the hddtemp platform."""
import socket import socket
import unittest import unittest
from unittest.mock import patch from unittest.mock import patch
from homeassistant.setup import setup_component from homeassistant.setup import setup_component
from tests.common import get_test_home_assistant from tests.common import get_test_home_assistant
VALID_CONFIG_MINIMAL = { VALID_CONFIG_MINIMAL = {
'sensor': { 'sensor': {
'platform': 'hddtemp', 'platform': 'hddtemp',
} }
} }
VALID_CONFIG_NAME = { VALID_CONFIG_NAME = {
'sensor': { 'sensor': {
'platform': 'hddtemp', 'platform': 'hddtemp',
'name': 'FooBar', 'name': 'FooBar',
} }
} }
VALID_CONFIG_ONE_DISK = { VALID_CONFIG_ONE_DISK = {
'sensor': { 'sensor': {
'platform': 'hddtemp', 'platform': 'hddtemp',
'disks': [ 'disks': [
'/dev/sdd1', '/dev/sdd1',
], ],
} }
} }
VALID_CONFIG_WRONG_DISK = { VALID_CONFIG_WRONG_DISK = {
'sensor': { 'sensor': {
'platform': 'hddtemp', 'platform': 'hddtemp',
'disks': [ 'disks': [
'/dev/sdx1', '/dev/sdx1',
], ],
} }
} }
VALID_CONFIG_MULTIPLE_DISKS = { VALID_CONFIG_MULTIPLE_DISKS = {
'sensor': { 'sensor': {
'platform': 'hddtemp', 'platform': 'hddtemp',
'host': 'foobar.local', 'host': 'foobar.local',
'disks': [ 'disks': [
'/dev/sda1', '/dev/sda1',
'/dev/sdb1', '/dev/sdb1',
'/dev/sdc1', '/dev/sdc1',
], ],
} }
} }
VALID_CONFIG_HOST = { VALID_CONFIG_HOST = {
'sensor': { 'sensor': {
'platform': 'hddtemp', 'platform': 'hddtemp',
'host': 'alice.local', 'host': 'alice.local',
} }
} }
VALID_CONFIG_HOST_UNREACHABLE = { VALID_CONFIG_HOST_UNREACHABLE = {
'sensor': { 'sensor': {
'platform': 'hddtemp', 'platform': 'hddtemp',
'host': 'bob.local', 'host': 'bob.local',
} }
} }
class TelnetMock(): class TelnetMock():
"""Mock class for the telnetlib.Telnet object.""" """Mock class for the telnetlib.Telnet object."""
def __init__(self, host, port, timeout=0): def __init__(self, host, port, timeout=0):
"""Initialize Telnet object.""" """Initialize Telnet object."""
self.host = host self.host = host
self.port = port self.port = port
self.timeout = timeout self.timeout = timeout
self.sample_data = bytes('|/dev/sda1|WDC WD30EZRX-12DC0B0|29|C|' + self.sample_data = bytes('|/dev/sda1|WDC WD30EZRX-12DC0B0|29|C|' +
'|/dev/sdb1|WDC WD15EADS-11P7B2|32|C|' + '|/dev/sdb1|WDC WD15EADS-11P7B2|32|C|' +
'|/dev/sdc1|WDC WD20EARX-22MMMB0|29|C|' + '|/dev/sdc1|WDC WD20EARX-22MMMB0|29|C|' +
'|/dev/sdd1|WDC WD15EARS-00Z5B1|89|F|', '|/dev/sdd1|WDC WD15EARS-00Z5B1|89|F|',
'ascii') 'ascii')
def read_all(self): def read_all(self):
"""Return sample values.""" """Return sample values."""
if self.host == 'alice.local': if self.host == 'alice.local':
raise ConnectionRefusedError raise ConnectionRefusedError
elif self.host == 'bob.local': elif self.host == 'bob.local':
raise socket.gaierror raise socket.gaierror
else: else:
return self.sample_data return self.sample_data
return None return None
class TestHDDTempSensor(unittest.TestCase): class TestHDDTempSensor(unittest.TestCase):
"""Test the hddtemp sensor.""" """Test the hddtemp sensor."""
def setUp(self): def setUp(self):
"""Set up things to run when tests begin.""" """Set up things to run when tests begin."""
self.hass = get_test_home_assistant() self.hass = get_test_home_assistant()
self.config = VALID_CONFIG_ONE_DISK self.config = VALID_CONFIG_ONE_DISK
self.reference = {'/dev/sda1': {'device': '/dev/sda1', self.reference = {'/dev/sda1': {'device': '/dev/sda1',
'temperature': '29', 'temperature': '29',
'unit_of_measurement': '°C', 'unit_of_measurement': '°C',
'model': 'WDC WD30EZRX-12DC0B0', }, 'model': 'WDC WD30EZRX-12DC0B0', },
'/dev/sdb1': {'device': '/dev/sdb1', '/dev/sdb1': {'device': '/dev/sdb1',
'temperature': '32', 'temperature': '32',
'unit_of_measurement': '°C', 'unit_of_measurement': '°C',
'model': 'WDC WD15EADS-11P7B2', }, 'model': 'WDC WD15EADS-11P7B2', },
'/dev/sdc1': {'device': '/dev/sdc1', '/dev/sdc1': {'device': '/dev/sdc1',
'temperature': '29', 'temperature': '29',
'unit_of_measurement': '°C', 'unit_of_measurement': '°C',
'model': 'WDC WD20EARX-22MMMB0', }, 'model': 'WDC WD20EARX-22MMMB0', },
'/dev/sdd1': {'device': '/dev/sdd1', '/dev/sdd1': {'device': '/dev/sdd1',
'temperature': '32', 'temperature': '32',
'unit_of_measurement': '°C', 'unit_of_measurement': '°C',
'model': 'WDC WD15EARS-00Z5B1', }, } 'model': 'WDC WD15EARS-00Z5B1', }, }
def tearDown(self): def tearDown(self):
"""Stop everything that was started.""" """Stop everything that was started."""
self.hass.stop() self.hass.stop()
@patch('telnetlib.Telnet', new=TelnetMock) @patch('telnetlib.Telnet', new=TelnetMock)
def test_hddtemp_min_config(self): def test_hddtemp_min_config(self):
"""Test minimal hddtemp configuration.""" """Test minimal hddtemp configuration."""
assert setup_component(self.hass, 'sensor', VALID_CONFIG_MINIMAL) assert setup_component(self.hass, 'sensor', VALID_CONFIG_MINIMAL)
entity = self.hass.states.all()[0].entity_id entity = self.hass.states.all()[0].entity_id
state = self.hass.states.get(entity) state = self.hass.states.get(entity)
reference = self.reference[state.attributes.get('device')] reference = self.reference[state.attributes.get('device')]
self.assertEqual(state.state, reference['temperature']) self.assertEqual(state.state, reference['temperature'])
self.assertEqual(state.attributes.get('device'), reference['device']) self.assertEqual(state.attributes.get('device'), reference['device'])
self.assertEqual(state.attributes.get('model'), reference['model']) self.assertEqual(state.attributes.get('model'), reference['model'])
self.assertEqual(state.attributes.get('unit_of_measurement'), self.assertEqual(state.attributes.get('unit_of_measurement'),
reference['unit_of_measurement']) reference['unit_of_measurement'])
self.assertEqual(state.attributes.get('friendly_name'), self.assertEqual(state.attributes.get('friendly_name'),
'HD Temperature ' + reference['device']) 'HD Temperature ' + reference['device'])
@patch('telnetlib.Telnet', new=TelnetMock) @patch('telnetlib.Telnet', new=TelnetMock)
def test_hddtemp_rename_config(self): def test_hddtemp_rename_config(self):
"""Test hddtemp configuration with different name.""" """Test hddtemp configuration with different name."""
assert setup_component(self.hass, 'sensor', VALID_CONFIG_NAME) assert setup_component(self.hass, 'sensor', VALID_CONFIG_NAME)
entity = self.hass.states.all()[0].entity_id entity = self.hass.states.all()[0].entity_id
state = self.hass.states.get(entity) state = self.hass.states.get(entity)
reference = self.reference[state.attributes.get('device')] reference = self.reference[state.attributes.get('device')]
self.assertEqual(state.attributes.get('friendly_name'), self.assertEqual(state.attributes.get('friendly_name'),
'FooBar ' + reference['device']) 'FooBar ' + reference['device'])
@patch('telnetlib.Telnet', new=TelnetMock) @patch('telnetlib.Telnet', new=TelnetMock)
def test_hddtemp_one_disk(self): def test_hddtemp_one_disk(self):
"""Test hddtemp one disk configuration.""" """Test hddtemp one disk configuration."""
assert setup_component(self.hass, 'sensor', VALID_CONFIG_ONE_DISK) assert setup_component(self.hass, 'sensor', VALID_CONFIG_ONE_DISK)
state = self.hass.states.get('sensor.hd_temperature_devsdd1') state = self.hass.states.get('sensor.hd_temperature_devsdd1')
reference = self.reference[state.attributes.get('device')] reference = self.reference[state.attributes.get('device')]
self.assertEqual(state.state, reference['temperature']) self.assertEqual(state.state, reference['temperature'])
self.assertEqual(state.attributes.get('device'), reference['device']) self.assertEqual(state.attributes.get('device'), reference['device'])
self.assertEqual(state.attributes.get('model'), reference['model']) self.assertEqual(state.attributes.get('model'), reference['model'])
self.assertEqual(state.attributes.get('unit_of_measurement'), self.assertEqual(state.attributes.get('unit_of_measurement'),
reference['unit_of_measurement']) reference['unit_of_measurement'])
self.assertEqual(state.attributes.get('friendly_name'), self.assertEqual(state.attributes.get('friendly_name'),
'HD Temperature ' + reference['device']) 'HD Temperature ' + reference['device'])
@patch('telnetlib.Telnet', new=TelnetMock) @patch('telnetlib.Telnet', new=TelnetMock)
def test_hddtemp_wrong_disk(self): def test_hddtemp_wrong_disk(self):
"""Test hddtemp wrong disk configuration.""" """Test hddtemp wrong disk configuration."""
assert setup_component(self.hass, 'sensor', VALID_CONFIG_WRONG_DISK) assert setup_component(self.hass, 'sensor', VALID_CONFIG_WRONG_DISK)
self.assertEqual(len(self.hass.states.all()), 1) self.assertEqual(len(self.hass.states.all()), 1)
state = self.hass.states.get('sensor.hd_temperature_devsdx1') state = self.hass.states.get('sensor.hd_temperature_devsdx1')
self.assertEqual(state.attributes.get('friendly_name'), self.assertEqual(state.attributes.get('friendly_name'),
'HD Temperature ' + '/dev/sdx1') 'HD Temperature ' + '/dev/sdx1')
@patch('telnetlib.Telnet', new=TelnetMock) @patch('telnetlib.Telnet', new=TelnetMock)
def test_hddtemp_multiple_disks(self): def test_hddtemp_multiple_disks(self):
"""Test hddtemp multiple disk configuration.""" """Test hddtemp multiple disk configuration."""
assert setup_component(self.hass, assert setup_component(self.hass,
'sensor', VALID_CONFIG_MULTIPLE_DISKS) 'sensor', VALID_CONFIG_MULTIPLE_DISKS)
for sensor in ['sensor.hd_temperature_devsda1', for sensor in ['sensor.hd_temperature_devsda1',
'sensor.hd_temperature_devsdb1', 'sensor.hd_temperature_devsdb1',
'sensor.hd_temperature_devsdc1']: 'sensor.hd_temperature_devsdc1']:
state = self.hass.states.get(sensor) state = self.hass.states.get(sensor)
reference = self.reference[state.attributes.get('device')] reference = self.reference[state.attributes.get('device')]
self.assertEqual(state.state, self.assertEqual(state.state,
reference['temperature']) reference['temperature'])
self.assertEqual(state.attributes.get('device'), self.assertEqual(state.attributes.get('device'),
reference['device']) reference['device'])
self.assertEqual(state.attributes.get('model'), self.assertEqual(state.attributes.get('model'),
reference['model']) reference['model'])
self.assertEqual(state.attributes.get('unit_of_measurement'), self.assertEqual(state.attributes.get('unit_of_measurement'),
reference['unit_of_measurement']) reference['unit_of_measurement'])
self.assertEqual(state.attributes.get('friendly_name'), self.assertEqual(state.attributes.get('friendly_name'),
'HD Temperature ' + reference['device']) 'HD Temperature ' + reference['device'])
@patch('telnetlib.Telnet', new=TelnetMock) @patch('telnetlib.Telnet', new=TelnetMock)
def test_hddtemp_host_refused(self): def test_hddtemp_host_refused(self):
"""Test hddtemp if host unreachable.""" """Test hddtemp if host unreachable."""
assert setup_component(self.hass, 'sensor', VALID_CONFIG_HOST) assert setup_component(self.hass, 'sensor', VALID_CONFIG_HOST)
self.assertEqual(len(self.hass.states.all()), 0) self.assertEqual(len(self.hass.states.all()), 0)
@patch('telnetlib.Telnet', new=TelnetMock) @patch('telnetlib.Telnet', new=TelnetMock)
def test_hddtemp_host_unreachable(self): def test_hddtemp_host_unreachable(self):
"""Test hddtemp if host unreachable.""" """Test hddtemp if host unreachable."""
assert setup_component(self.hass, 'sensor', assert setup_component(self.hass, 'sensor',
VALID_CONFIG_HOST_UNREACHABLE) VALID_CONFIG_HOST_UNREACHABLE)
self.assertEqual(len(self.hass.states.all()), 0) self.assertEqual(len(self.hass.states.all()), 0)

View File

@ -1,192 +1,192 @@
"""The tests for the wake on lan switch platform.""" """The tests for the wake on lan switch platform."""
import unittest import unittest
from unittest.mock import patch from unittest.mock import patch
from homeassistant.setup import setup_component from homeassistant.setup import setup_component
from homeassistant.const import STATE_ON, STATE_OFF from homeassistant.const import STATE_ON, STATE_OFF
import homeassistant.components.switch as switch import homeassistant.components.switch as switch
from tests.common import get_test_home_assistant, mock_service from tests.common import get_test_home_assistant, mock_service
TEST_STATE = None TEST_STATE = None
def send_magic_packet(*macs, **kwargs): def send_magic_packet(*macs, **kwargs):
"""Fake call for sending magic packets.""" """Fake call for sending magic packets."""
return return
def call(cmd, stdout, stderr): def call(cmd, stdout, stderr):
"""Return fake subprocess return codes.""" """Return fake subprocess return codes."""
if cmd[5] == 'validhostname' and TEST_STATE: if cmd[5] == 'validhostname' and TEST_STATE:
return 0 return 0
return 2 return 2
def system(): def system():
"""Fake system call to test the windows platform.""" """Fake system call to test the windows platform."""
return 'Windows' return 'Windows'
class TestWOLSwitch(unittest.TestCase): class TestWOLSwitch(unittest.TestCase):
"""Test the wol switch.""" """Test the wol switch."""
def setUp(self): def setUp(self):
"""Setup things to be run when tests are started.""" """Setup things to be run when tests are started."""
self.hass = get_test_home_assistant() self.hass = get_test_home_assistant()
def tearDown(self): def tearDown(self):
"""Stop everything that was started.""" """Stop everything that was started."""
self.hass.stop() self.hass.stop()
@patch('wakeonlan.send_magic_packet', new=send_magic_packet) @patch('wakeonlan.send_magic_packet', new=send_magic_packet)
@patch('subprocess.call', new=call) @patch('subprocess.call', new=call)
def test_valid_hostname(self): def test_valid_hostname(self):
"""Test with valid hostname.""" """Test with valid hostname."""
global TEST_STATE global TEST_STATE
TEST_STATE = False TEST_STATE = False
self.assertTrue(setup_component(self.hass, switch.DOMAIN, { self.assertTrue(setup_component(self.hass, switch.DOMAIN, {
'switch': { 'switch': {
'platform': 'wake_on_lan', 'platform': 'wake_on_lan',
'mac_address': '00-01-02-03-04-05', 'mac_address': '00-01-02-03-04-05',
'host': 'validhostname', 'host': 'validhostname',
} }
})) }))
state = self.hass.states.get('switch.wake_on_lan') state = self.hass.states.get('switch.wake_on_lan')
self.assertEqual(STATE_OFF, state.state) self.assertEqual(STATE_OFF, state.state)
TEST_STATE = True TEST_STATE = True
switch.turn_on(self.hass, 'switch.wake_on_lan') switch.turn_on(self.hass, 'switch.wake_on_lan')
self.hass.block_till_done() self.hass.block_till_done()
state = self.hass.states.get('switch.wake_on_lan') state = self.hass.states.get('switch.wake_on_lan')
self.assertEqual(STATE_ON, state.state) self.assertEqual(STATE_ON, state.state)
switch.turn_off(self.hass, 'switch.wake_on_lan') switch.turn_off(self.hass, 'switch.wake_on_lan')
self.hass.block_till_done() self.hass.block_till_done()
state = self.hass.states.get('switch.wake_on_lan') state = self.hass.states.get('switch.wake_on_lan')
self.assertEqual(STATE_ON, state.state) self.assertEqual(STATE_ON, state.state)
@patch('wakeonlan.send_magic_packet', new=send_magic_packet) @patch('wakeonlan.send_magic_packet', new=send_magic_packet)
@patch('subprocess.call', new=call) @patch('subprocess.call', new=call)
@patch('platform.system', new=system) @patch('platform.system', new=system)
def test_valid_hostname_windows(self): def test_valid_hostname_windows(self):
"""Test with valid hostname on windows.""" """Test with valid hostname on windows."""
global TEST_STATE global TEST_STATE
TEST_STATE = False TEST_STATE = False
self.assertTrue(setup_component(self.hass, switch.DOMAIN, { self.assertTrue(setup_component(self.hass, switch.DOMAIN, {
'switch': { 'switch': {
'platform': 'wake_on_lan', 'platform': 'wake_on_lan',
'mac_address': '00-01-02-03-04-05', 'mac_address': '00-01-02-03-04-05',
'host': 'validhostname', 'host': 'validhostname',
} }
})) }))
state = self.hass.states.get('switch.wake_on_lan') state = self.hass.states.get('switch.wake_on_lan')
self.assertEqual(STATE_OFF, state.state) self.assertEqual(STATE_OFF, state.state)
TEST_STATE = True TEST_STATE = True
switch.turn_on(self.hass, 'switch.wake_on_lan') switch.turn_on(self.hass, 'switch.wake_on_lan')
self.hass.block_till_done() self.hass.block_till_done()
state = self.hass.states.get('switch.wake_on_lan') state = self.hass.states.get('switch.wake_on_lan')
self.assertEqual(STATE_ON, state.state) self.assertEqual(STATE_ON, state.state)
@patch('wakeonlan.send_magic_packet', new=send_magic_packet) @patch('wakeonlan.send_magic_packet', new=send_magic_packet)
@patch('subprocess.call', new=call) @patch('subprocess.call', new=call)
def test_minimal_config(self): def test_minimal_config(self):
"""Test with minimal config.""" """Test with minimal config."""
self.assertTrue(setup_component(self.hass, switch.DOMAIN, { self.assertTrue(setup_component(self.hass, switch.DOMAIN, {
'switch': { 'switch': {
'platform': 'wake_on_lan', 'platform': 'wake_on_lan',
'mac_address': '00-01-02-03-04-05', 'mac_address': '00-01-02-03-04-05',
} }
})) }))
@patch('wakeonlan.send_magic_packet', new=send_magic_packet) @patch('wakeonlan.send_magic_packet', new=send_magic_packet)
@patch('subprocess.call', new=call) @patch('subprocess.call', new=call)
def test_broadcast_config(self): def test_broadcast_config(self):
"""Test with broadcast address config.""" """Test with broadcast address config."""
self.assertTrue(setup_component(self.hass, switch.DOMAIN, { self.assertTrue(setup_component(self.hass, switch.DOMAIN, {
'switch': { 'switch': {
'platform': 'wake_on_lan', 'platform': 'wake_on_lan',
'mac_address': '00-01-02-03-04-05', 'mac_address': '00-01-02-03-04-05',
'broadcast_address': '255.255.255.255', 'broadcast_address': '255.255.255.255',
} }
})) }))
state = self.hass.states.get('switch.wake_on_lan') state = self.hass.states.get('switch.wake_on_lan')
self.assertEqual(STATE_OFF, state.state) self.assertEqual(STATE_OFF, state.state)
switch.turn_on(self.hass, 'switch.wake_on_lan') switch.turn_on(self.hass, 'switch.wake_on_lan')
self.hass.block_till_done() self.hass.block_till_done()
@patch('wakeonlan.send_magic_packet', new=send_magic_packet) @patch('wakeonlan.send_magic_packet', new=send_magic_packet)
@patch('subprocess.call', new=call) @patch('subprocess.call', new=call)
def test_off_script(self): def test_off_script(self):
"""Test with turn off script.""" """Test with turn off script."""
global TEST_STATE global TEST_STATE
TEST_STATE = False TEST_STATE = False
self.assertTrue(setup_component(self.hass, switch.DOMAIN, { self.assertTrue(setup_component(self.hass, switch.DOMAIN, {
'switch': { 'switch': {
'platform': 'wake_on_lan', 'platform': 'wake_on_lan',
'mac_address': '00-01-02-03-04-05', 'mac_address': '00-01-02-03-04-05',
'host': 'validhostname', 'host': 'validhostname',
'turn_off': { 'turn_off': {
'service': 'shell_command.turn_off_TARGET', 'service': 'shell_command.turn_off_TARGET',
}, },
} }
})) }))
calls = mock_service(self.hass, 'shell_command', 'turn_off_TARGET') calls = mock_service(self.hass, 'shell_command', 'turn_off_TARGET')
state = self.hass.states.get('switch.wake_on_lan') state = self.hass.states.get('switch.wake_on_lan')
self.assertEqual(STATE_OFF, state.state) self.assertEqual(STATE_OFF, state.state)
TEST_STATE = True TEST_STATE = True
switch.turn_on(self.hass, 'switch.wake_on_lan') switch.turn_on(self.hass, 'switch.wake_on_lan')
self.hass.block_till_done() self.hass.block_till_done()
state = self.hass.states.get('switch.wake_on_lan') state = self.hass.states.get('switch.wake_on_lan')
self.assertEqual(STATE_ON, state.state) self.assertEqual(STATE_ON, state.state)
assert len(calls) == 0 assert len(calls) == 0
TEST_STATE = False TEST_STATE = False
switch.turn_off(self.hass, 'switch.wake_on_lan') switch.turn_off(self.hass, 'switch.wake_on_lan')
self.hass.block_till_done() self.hass.block_till_done()
state = self.hass.states.get('switch.wake_on_lan') state = self.hass.states.get('switch.wake_on_lan')
self.assertEqual(STATE_OFF, state.state) self.assertEqual(STATE_OFF, state.state)
assert len(calls) == 1 assert len(calls) == 1
@patch('wakeonlan.send_magic_packet', new=send_magic_packet) @patch('wakeonlan.send_magic_packet', new=send_magic_packet)
@patch('subprocess.call', new=call) @patch('subprocess.call', new=call)
@patch('platform.system', new=system) @patch('platform.system', new=system)
def test_invalid_hostname_windows(self): def test_invalid_hostname_windows(self):
"""Test with invalid hostname on windows.""" """Test with invalid hostname on windows."""
global TEST_STATE global TEST_STATE
TEST_STATE = False TEST_STATE = False
self.assertTrue(setup_component(self.hass, switch.DOMAIN, { self.assertTrue(setup_component(self.hass, switch.DOMAIN, {
'switch': { 'switch': {
'platform': 'wake_on_lan', 'platform': 'wake_on_lan',
'mac_address': '00-01-02-03-04-05', 'mac_address': '00-01-02-03-04-05',
'host': 'invalidhostname', 'host': 'invalidhostname',
} }
})) }))
state = self.hass.states.get('switch.wake_on_lan') state = self.hass.states.get('switch.wake_on_lan')
self.assertEqual(STATE_OFF, state.state) self.assertEqual(STATE_OFF, state.state)
TEST_STATE = True TEST_STATE = True
switch.turn_on(self.hass, 'switch.wake_on_lan') switch.turn_on(self.hass, 'switch.wake_on_lan')
self.hass.block_till_done() self.hass.block_till_done()
state = self.hass.states.get('switch.wake_on_lan') state = self.hass.states.get('switch.wake_on_lan')
self.assertEqual(STATE_OFF, state.state) self.assertEqual(STATE_OFF, state.state)