""" tests.common ~~~~~~~~~~~~ Helper method for writing tests. """ import os from datetime import timedelta from unittest import mock from homeassistant import core as ha, loader from homeassistant.helpers.entity import ToggleEntity from homeassistant.const import ( STATE_ON, STATE_OFF, DEVICE_DEFAULT_NAME, EVENT_TIME_CHANGED, EVENT_STATE_CHANGED, EVENT_PLATFORM_DISCOVERED, ATTR_SERVICE, ATTR_DISCOVERED) from homeassistant.components import sun, mqtt def get_test_config_dir(): """ Returns a path to a test config dir. """ return os.path.join(os.path.dirname(__file__), "config") def get_test_home_assistant(num_threads=None): """ Returns a Home Assistant object pointing at test config dir. """ if num_threads: orig_num_threads = ha.MIN_WORKER_THREAD ha.MIN_WORKER_THREAD = num_threads hass = ha.HomeAssistant() if num_threads: ha.MIN_WORKER_THREAD = orig_num_threads hass.config.config_dir = get_test_config_dir() hass.config.latitude = 32.87336 hass.config.longitude = -117.22743 if 'custom_components.test' not in loader.AVAILABLE_COMPONENTS: loader.prepare(hass) return hass def mock_service(hass, domain, service): """ Sets up a fake service. Returns a list that logs all calls to fake service. """ calls = [] hass.services.register( domain, service, lambda call: calls.append(call)) return calls def fire_mqtt_message(hass, topic, payload, qos=0): hass.bus.fire(mqtt.EVENT_MQTT_MESSAGE_RECEIVED, { mqtt.ATTR_TOPIC: topic, mqtt.ATTR_PAYLOAD: payload, mqtt.ATTR_QOS: qos, }) def fire_time_changed(hass, time): hass.bus.fire(EVENT_TIME_CHANGED, {'now': time}) def fire_service_discovered(hass, service, info): hass.bus.fire(EVENT_PLATFORM_DISCOVERED, { ATTR_SERVICE: service, ATTR_DISCOVERED: info }) def ensure_sun_risen(hass): """ Trigger sun to rise if below horizon. """ if sun.is_on(hass): return fire_time_changed(hass, sun.next_rising_utc(hass) + timedelta(seconds=10)) def ensure_sun_set(hass): """ Trigger sun to set if above horizon. """ if not sun.is_on(hass): return fire_time_changed(hass, sun.next_setting_utc(hass) + timedelta(seconds=10)) def mock_state_change_event(hass, new_state, old_state=None): event_data = { 'entity_id': new_state.entity_id, 'new_state': new_state, } if old_state: event_data['old_state'] = old_state hass.bus.fire(EVENT_STATE_CHANGED, event_data) def mock_http_component(hass): hass.http = MockHTTP() hass.config.components.append('http') @mock.patch('homeassistant.components.mqtt.MQTT') def mock_mqtt_component(hass, mock_mqtt): mqtt.setup(hass, { mqtt.DOMAIN: { mqtt.CONF_BROKER: 'mock-broker', } }) hass.config.components.append(mqtt.DOMAIN) return mock_mqtt class MockHTTP(object): """ Mocks the HTTP module. """ def register_path(self, method, url, callback, require_auth=True): pass class MockModule(object): """ Provides a fake module. """ def __init__(self, domain=None, dependencies=[], setup=None): self.DOMAIN = domain self.DEPENDENCIES = dependencies # Setup a mock setup if none given. if setup is None: self.setup = lambda hass, config: False else: self.setup = setup class MockPlatform(object): """ Provides a fake platform. """ def __init__(self, setup_platform=None, dependencies=[]): self.DEPENDENCIES = dependencies self._setup_platform = setup_platform def setup_platform(self, hass, config, add_devices, discovery_info=None): if self._setup_platform is not None: self._setup_platform(hass, config, add_devices, discovery_info) class MockToggleDevice(ToggleEntity): """ Provides a mock toggle device. """ def __init__(self, name, state): self._name = name or DEVICE_DEFAULT_NAME self._state = state self.calls = [] @property def name(self): """ Returns the name of the device if any. """ self.calls.append(('name', {})) return self._name @property def state(self): """ Returns the name of the device if any. """ self.calls.append(('state', {})) return self._state @property def is_on(self): """ True if device is on. """ self.calls.append(('is_on', {})) return self._state == STATE_ON def turn_on(self, **kwargs): """ Turn the device on. """ self.calls.append(('turn_on', kwargs)) self._state = STATE_ON def turn_off(self, **kwargs): """ Turn the device off. """ self.calls.append(('turn_off', kwargs)) self._state = STATE_OFF def last_call(self, method=None): if not self.calls: return None elif method is None: return self.calls[-1] else: try: return next(call for call in reversed(self.calls) if call[0] == method) except StopIteration: return None