Load requirements and dependencies from manifests. Fallback to current REQUIREMENTS and DEPENDENCIES (#22717)

* Load dependencies from manifests. Fallback to current DEPENDENCIES

* Fix typing

* Ignore typing correctly

* Split out dependency processing to a new method

* Fix tests

* Only pull from manifest if dependencies is non empty

* Inline temporary function

* Fix light tests [skip ci]

* Fix tests/common

* Fix some mqtt tests [skip ci]

* Fix tests and component manifests which have only one platform

* Fix rflink tests

* Fix more tests and manifests

* Readability over shorthand format

* Fix demo/notify tests

* Load dependencies from manifests. Fallback to current DEPENDENCIES

* Load requirements from manifests. Fallback to current REQUIREMENTS

* Fix typing

* Ignore typing correctly

* Split out dependency processing to a new method

* Only pull from manifest if dependencies is non empty

* Inline temporary function

* Fix tests and component manifests which have only one platform

* Fix rflink tests

* Readability over shorthand format

* Clean up requirements

* Use integration to resolve deps/reqs

* Lint

* Lint

* revert a change

* Revert a test change

* Fix types

* Fix types

* Add back cache for load component

* Fix test_component_not_found

* Move light.test and device_tracker.test into test package instead with manifest to fix tests

* Fix broken device_tracker tests

* Add docstrings to __init__

* Fix all of the light tests that I broke earlier

* Embed the test.switch platform to fix other tests

* Embed and fix the test.imagimage_processing platform

* Fix tests for nx584

* Add dependencies from platform file's DEPENDENCIES

* Try to setup component when entity_platform is setting up

Fix tests in helpers folder

* Rewrite test_setup

* Simplify

* Lint

* Disable demo component if running in test

Temp workaround to unblock CI tests

* Skip demo tests

* Fix config entry test

* Fix repeat test

* Clarify doc

* One extra guard

* Fix import

* Lint

* Workaround google tts
This commit is contained in:
Rohan Kapoor 2019-04-11 01:26:36 -07:00 committed by Jason Hu
parent 8a81286abb
commit 6ba9ccf052
66 changed files with 391 additions and 233 deletions

View File

@ -5,6 +5,8 @@
"requirements": [ "requirements": [
"pyarlo==0.2.3" "pyarlo==0.2.3"
], ],
"dependencies": [], "dependencies": [
"ffmpeg"
],
"codeowners": [] "codeowners": []
} }

View File

@ -3,6 +3,8 @@
"name": "Arwn", "name": "Arwn",
"documentation": "https://www.home-assistant.io/components/arwn", "documentation": "https://www.home-assistant.io/components/arwn",
"requirements": [], "requirements": [],
"dependencies": [], "dependencies": [
"mqtt"
],
"codeowners": [] "codeowners": []
} }

View File

@ -3,6 +3,8 @@
"name": "Asterisk cdr", "name": "Asterisk cdr",
"documentation": "https://www.home-assistant.io/components/asterisk_cdr", "documentation": "https://www.home-assistant.io/components/asterisk_cdr",
"requirements": [], "requirements": [],
"dependencies": [], "dependencies": [
"asterisk_mbox"
],
"codeowners": [] "codeowners": []
} }

View File

@ -5,7 +5,9 @@
"requirements": [ "requirements": [
"aioautomatic==0.6.5" "aioautomatic==0.6.5"
], ],
"dependencies": [], "dependencies": [
"http"
],
"codeowners": [ "codeowners": [
"@armills" "@armills"
] ]

View File

@ -4,7 +4,8 @@
"documentation": "https://www.home-assistant.io/components/automation", "documentation": "https://www.home-assistant.io/components/automation",
"requirements": [], "requirements": [],
"dependencies": [ "dependencies": [
"group" "group",
"webhook"
], ],
"codeowners": [ "codeowners": [
"@home-assistant/core" "@home-assistant/core"

View File

@ -5,6 +5,8 @@
"requirements": [ "requirements": [
"py-canary==0.5.0" "py-canary==0.5.0"
], ],
"dependencies": [], "dependencies": [
"ffmpeg"
],
"codeowners": [] "codeowners": []
} }

View File

@ -1,6 +1,7 @@
"""Set up the demo environment that mimics interaction with devices.""" """Set up the demo environment that mimics interaction with devices."""
import asyncio import asyncio
import time import time
import sys
from homeassistant import bootstrap from homeassistant import bootstrap
import homeassistant.core as ha import homeassistant.core as ha
@ -31,7 +32,7 @@ COMPONENTS_WITH_DEMO_PLATFORM = [
] ]
async def async_setup(hass, config): async def _async_setup(hass, config):
"""Set up the demo environment.""" """Set up the demo environment."""
group = hass.components.group group = hass.components.group
configurator = hass.components.configurator configurator = hass.components.configurator
@ -224,3 +225,7 @@ async def async_setup(hass, config):
hass.async_add_job(setup_configurator) hass.async_add_job(setup_configurator)
return True return True
if 'pytest' not in sys.modules:
async_setup = _async_setup # pylint: disable=invalid-name

View File

@ -5,7 +5,9 @@
"requirements": [ "requirements": [
"fitbit==0.3.0" "fitbit==0.3.0"
], ],
"dependencies": [], "dependencies": [
"http"
],
"codeowners": [ "codeowners": [
"@robbiet480" "@robbiet480"
] ]

View File

@ -5,6 +5,8 @@
"requirements": [ "requirements": [
"pyflexit==0.3" "pyflexit==0.3"
], ],
"dependencies": [], "dependencies": [
"modbus"
],
"codeowners": [] "codeowners": []
} }

View File

@ -3,6 +3,8 @@
"name": "Flux", "name": "Flux",
"documentation": "https://www.home-assistant.io/components/flux", "documentation": "https://www.home-assistant.io/components/flux",
"requirements": [], "requirements": [],
"dependencies": [], "dependencies": [
"light"
],
"codeowners": [] "codeowners": []
} }

View File

@ -3,6 +3,9 @@
"name": "Generic thermostat", "name": "Generic thermostat",
"documentation": "https://www.home-assistant.io/components/generic_thermostat", "documentation": "https://www.home-assistant.io/components/generic_thermostat",
"requirements": [], "requirements": [],
"dependencies": [], "dependencies": [
"sensor",
"switch"
],
"codeowners": [] "codeowners": []
} }

View File

@ -153,6 +153,9 @@ def setup(hass, config):
hass.data[DATA_INDEX] = {} hass.data[DATA_INDEX] = {}
conf = config.get(DOMAIN, {}) conf = config.get(DOMAIN, {})
if not conf:
# component is set up by tts platform
return True
token_file = hass.config.path(TOKEN_FILE) token_file = hass.config.path(TOKEN_FILE)
if not os.path.isfile(token_file): if not os.path.isfile(token_file):

View File

@ -3,6 +3,8 @@
"name": "History stats", "name": "History stats",
"documentation": "https://www.home-assistant.io/components/history_stats", "documentation": "https://www.home-assistant.io/components/history_stats",
"requirements": [], "requirements": [],
"dependencies": [], "dependencies": [
"history"
],
"codeowners": [] "codeowners": []
} }

View File

@ -3,6 +3,8 @@
"name": "Manual mqtt", "name": "Manual mqtt",
"documentation": "https://www.home-assistant.io/components/manual_mqtt", "documentation": "https://www.home-assistant.io/components/manual_mqtt",
"requirements": [], "requirements": [],
"dependencies": [], "dependencies": [
"mqtt"
],
"codeowners": [] "codeowners": []
} }

View File

@ -6,7 +6,9 @@
"hbmqtt==0.9.4", "hbmqtt==0.9.4",
"paho-mqtt==1.4.0" "paho-mqtt==1.4.0"
], ],
"dependencies": [], "dependencies": [
"http"
],
"codeowners": [ "codeowners": [
"@home-assistant/core" "@home-assistant/core"
] ]

View File

@ -3,6 +3,8 @@
"name": "Mqtt json", "name": "Mqtt json",
"documentation": "https://www.home-assistant.io/components/mqtt_json", "documentation": "https://www.home-assistant.io/components/mqtt_json",
"requirements": [], "requirements": [],
"dependencies": [], "dependencies": [
"mqtt"
],
"codeowners": [] "codeowners": []
} }

View File

@ -3,6 +3,8 @@
"name": "Mqtt room", "name": "Mqtt room",
"documentation": "https://www.home-assistant.io/components/mqtt_room", "documentation": "https://www.home-assistant.io/components/mqtt_room",
"requirements": [], "requirements": [],
"dependencies": [], "dependencies": [
"mqtt"
],
"codeowners": [] "codeowners": []
} }

View File

@ -5,7 +5,9 @@
"requirements": [ "requirements": [
"python-mystrom==0.5.0" "python-mystrom==0.5.0"
], ],
"dependencies": [], "dependencies": [
"http"
],
"codeowners": [ "codeowners": [
"@fabaff" "@fabaff"
] ]

View File

@ -3,6 +3,8 @@
"name": "Netatmo public", "name": "Netatmo public",
"documentation": "https://www.home-assistant.io/components/netatmo_public", "documentation": "https://www.home-assistant.io/components/netatmo_public",
"requirements": [], "requirements": [],
"dependencies": [], "dependencies": [
"netatmo"
],
"codeowners": [] "codeowners": []
} }

View File

@ -5,6 +5,8 @@
"requirements": [ "requirements": [
"pynetio==0.1.9.1" "pynetio==0.1.9.1"
], ],
"dependencies": [], "dependencies": [
"http"
],
"codeowners": [] "codeowners": []
} }

View File

@ -7,6 +7,8 @@
"suds-passworddigest-homeassistant==0.1.2a0.dev0", "suds-passworddigest-homeassistant==0.1.2a0.dev0",
"suds-py3==1.3.3.0" "suds-py3==1.3.3.0"
], ],
"dependencies": [], "dependencies": [
"ffmpeg"
],
"codeowners": [] "codeowners": []
} }

View File

@ -5,6 +5,8 @@
"requirements": [ "requirements": [
"ring_doorbell==0.2.3" "ring_doorbell==0.2.3"
], ],
"dependencies": [], "dependencies": [
"ffmpeg"
],
"codeowners": [] "codeowners": []
} }

View File

@ -5,6 +5,8 @@
"requirements": [ "requirements": [
"spotipy-homeassistant==2.4.4.dev1" "spotipy-homeassistant==2.4.4.dev1"
], ],
"dependencies": [], "dependencies": [
"http"
],
"codeowners": [] "codeowners": []
} }

View File

@ -3,6 +3,8 @@
"name": "Telegram", "name": "Telegram",
"documentation": "https://www.home-assistant.io/components/telegram", "documentation": "https://www.home-assistant.io/components/telegram",
"requirements": [], "requirements": [],
"dependencies": [], "dependencies": [
"telegram_bot"
],
"codeowners": [] "codeowners": []
} }

View File

@ -5,6 +5,8 @@
"requirements": [ "requirements": [
"VL53L1X2==0.1.5" "VL53L1X2==0.1.5"
], ],
"dependencies": [], "dependencies": [
"rpi_gpio"
],
"codeowners": [] "codeowners": []
} }

View File

@ -3,6 +3,8 @@
"name": "Torque", "name": "Torque",
"documentation": "https://www.home-assistant.io/components/torque", "documentation": "https://www.home-assistant.io/components/torque",
"requirements": [], "requirements": [],
"dependencies": [], "dependencies": [
"http"
],
"codeowners": [] "codeowners": []
} }

View File

@ -3,7 +3,9 @@
"name": "Twilio call", "name": "Twilio call",
"documentation": "https://www.home-assistant.io/components/twilio_call", "documentation": "https://www.home-assistant.io/components/twilio_call",
"requirements": [], "requirements": [],
"dependencies": [], "dependencies": [
"twilio"
],
"codeowners": [ "codeowners": [
"@robbiet480" "@robbiet480"
] ]

View File

@ -3,7 +3,9 @@
"name": "Twilio sms", "name": "Twilio sms",
"documentation": "https://www.home-assistant.io/components/twilio_sms", "documentation": "https://www.home-assistant.io/components/twilio_sms",
"requirements": [], "requirements": [],
"dependencies": [], "dependencies": [
"twilio"
],
"codeowners": [ "codeowners": [
"@robbiet480" "@robbiet480"
] ]

View File

@ -3,6 +3,8 @@
"name": "Xiaomi", "name": "Xiaomi",
"documentation": "https://www.home-assistant.io/components/xiaomi", "documentation": "https://www.home-assistant.io/components/xiaomi",
"requirements": [], "requirements": [],
"dependencies": [], "dependencies": [
"ffmpeg"
],
"codeowners": [] "codeowners": []
} }

View File

@ -5,7 +5,9 @@
"requirements": [ "requirements": [
"aioftp==0.12.0" "aioftp==0.12.0"
], ],
"dependencies": [], "dependencies": [
"ffmpeg"
],
"codeowners": [ "codeowners": [
"@bachya" "@bachya"
] ]

View File

@ -126,7 +126,7 @@ import uuid
from typing import Callable, Dict, List, Optional, Set # noqa pylint: disable=unused-import from typing import Callable, Dict, List, Optional, Set # noqa pylint: disable=unused-import
import weakref import weakref
from homeassistant import data_entry_flow from homeassistant import data_entry_flow, loader
from homeassistant.core import callback, HomeAssistant from homeassistant.core import callback, HomeAssistant
from homeassistant.exceptions import HomeAssistantError, ConfigEntryNotReady from homeassistant.exceptions import HomeAssistantError, ConfigEntryNotReady
from homeassistant.setup import async_setup_component, async_process_deps_reqs from homeassistant.setup import async_setup_component, async_process_deps_reqs
@ -688,7 +688,12 @@ class ConfigEntries:
Handler key is the domain of the component that we want to set up. Handler key is the domain of the component that we want to set up.
""" """
component = getattr(self.hass.components, handler_key) integration = await loader.async_get_integration(
self.hass, handler_key)
if integration is None:
raise data_entry_flow.UnknownHandler
handler = HANDLERS.get(handler_key) handler = HANDLERS.get(handler_key)
if handler is None: if handler is None:
@ -698,7 +703,7 @@ class ConfigEntries:
# Make sure requirements and dependencies of component are resolved # Make sure requirements and dependencies of component are resolved
await async_process_deps_reqs( await async_process_deps_reqs(
self.hass, self._hass_config, handler, component) self.hass, self._hass_config, integration)
# Create notification. # Create notification.
if source in DISCOVERY_SOURCES: if source in DISCOVERY_SOURCES:

View File

@ -52,11 +52,11 @@ LOOKUP_PATHS = [PACKAGE_CUSTOM_COMPONENTS, PACKAGE_BUILTIN]
_UNDEF = object() _UNDEF = object()
def manifest_from_legacy_module(module: Any) -> Dict: def manifest_from_legacy_module(module: ModuleType) -> Dict:
"""Generate a manifest from a legacy module.""" """Generate a manifest from a legacy module."""
return { return {
'domain': module.DOMAIN, 'domain': module.DOMAIN, # type: ignore
'name': module.DOMAIN, 'name': module.DOMAIN, # type: ignore
'documentation': None, 'documentation': None,
'requirements': getattr(module, 'REQUIREMENTS', []), 'requirements': getattr(module, 'REQUIREMENTS', []),
'dependencies': getattr(module, 'DEPENDENCIES', []), 'dependencies': getattr(module, 'DEPENDENCIES', []),
@ -68,10 +68,10 @@ class Integration:
"""An integration in Home Assistant.""" """An integration in Home Assistant."""
@classmethod @classmethod
def resolve_from_root(cls, hass: 'HomeAssistant', root_module: Any, def resolve_from_root(cls, hass: 'HomeAssistant', root_module: ModuleType,
domain: str) -> 'Optional[Integration]': domain: str) -> 'Optional[Integration]':
"""Resolve an integration from a root module.""" """Resolve an integration from a root module."""
for base in root_module.__path__: for base in root_module.__path__: # type: ignore
manifest_path = ( manifest_path = (
pathlib.Path(base) / domain / 'manifest.json' pathlib.Path(base) / domain / 'manifest.json'
) )
@ -117,15 +117,22 @@ class Integration:
self.dependencies = manifest['dependencies'] # type: List[str] self.dependencies = manifest['dependencies'] # type: List[str]
self.requirements = manifest['requirements'] # type: List[str] self.requirements = manifest['requirements'] # type: List[str]
def get_component(self) -> Any: def get_component(self) -> ModuleType:
"""Return the component.""" """Return the component."""
return importlib.import_module(self.pkg_path) cache = self.hass.data.setdefault(DATA_KEY, {})
if self.domain not in cache:
cache[self.domain] = importlib.import_module(self.pkg_path)
return cache[self.domain] # type: ignore
def get_platform(self, platform_name: str) -> Any: def get_platform(self, platform_name: str) -> ModuleType:
"""Return a platform for an integration.""" """Return a platform for an integration."""
return importlib.import_module( cache = self.hass.data.setdefault(DATA_KEY, {})
full_name = "{}.{}".format(self.domain, platform_name)
if full_name not in cache:
cache[full_name] = importlib.import_module(
"{}.{}".format(self.pkg_path, platform_name) "{}.{}".format(self.pkg_path, platform_name)
) )
return cache[full_name] # type: ignore
async def async_get_integration(hass: 'HomeAssistant', domain: str)\ async def async_get_integration(hass: 'HomeAssistant', domain: str)\

View File

@ -100,10 +100,16 @@ async def _async_setup_component(hass: core.HomeAssistant,
_LOGGER.error("Setup failed for %s: %s", domain, msg) _LOGGER.error("Setup failed for %s: %s", domain, msg)
async_notify_setup_error(hass, domain, link) async_notify_setup_error(hass, domain, link)
component = loader.get_component(hass, domain) try:
integration = await loader.async_get_integration(hass, domain)
except loader.IntegrationNotFound:
log_error("Integration not found.", False)
return False
if not component: try:
log_error("Component not found.", False) component = integration.get_component()
except ImportError:
log_error("Unable to import component", False)
return False return False
# Validate all dependencies exist and there are no circular dependencies # Validate all dependencies exist and there are no circular dependencies
@ -128,7 +134,7 @@ async def _async_setup_component(hass: core.HomeAssistant,
return False return False
try: try:
await async_process_deps_reqs(hass, config, domain, component) await async_process_deps_reqs(hass, config, integration)
except HomeAssistantError as err: except HomeAssistantError as err:
log_error(str(err)) log_error(str(err))
return False return False
@ -189,7 +195,8 @@ async def _async_setup_component(hass: core.HomeAssistant,
return True return True
async def async_prepare_setup_platform(hass: core.HomeAssistant, config: Dict, async def async_prepare_setup_platform(hass: core.HomeAssistant,
hass_config: Dict,
domain: str, platform_name: str) \ domain: str, platform_name: str) \
-> Optional[ModuleType]: -> Optional[ModuleType]:
"""Load a platform and makes sure dependencies are setup. """Load a platform and makes sure dependencies are setup.
@ -202,13 +209,18 @@ async def async_prepare_setup_platform(hass: core.HomeAssistant, config: Dict,
def log_error(msg: str) -> None: def log_error(msg: str) -> None:
"""Log helper.""" """Log helper."""
_LOGGER.error("Unable to prepare setup for platform %s: %s", _LOGGER.error("Unable to prepare setup for platform %s: %s",
platform_path, msg) platform_name, msg)
async_notify_setup_error(hass, platform_path) async_notify_setup_error(hass, platform_path)
platform = loader.get_platform(hass, domain, platform_name) try:
integration = await loader.async_get_integration(hass, platform_name)
except loader.IntegrationNotFound:
log_error("Integration not found")
return None
# Not found try:
if platform is None: platform = integration.get_platform(domain)
except ImportError:
log_error("Platform not found.") log_error("Platform not found.")
return None return None
@ -216,9 +228,25 @@ async def async_prepare_setup_platform(hass: core.HomeAssistant, config: Dict,
if platform_path in hass.config.components: if platform_path in hass.config.components:
return platform return platform
# Platforms cannot exist on their own, they are part of their integration.
# If the integration is not set up yet, and can be set up, set it up.
if integration.domain not in hass.config.components:
try: try:
await async_process_deps_reqs( component = integration.get_component()
hass, config, platform_path, platform) except ImportError:
log_error("Unable to import the component")
return None
if (hasattr(component, 'setup')
or hasattr(component, 'async_setup')):
if not await async_setup_component(
hass, integration.domain, hass_config
):
log_error("Unable to set up component.")
return None
try:
await async_process_deps_reqs(hass, hass_config, integration)
except HomeAssistantError as err: except HomeAssistantError as err:
log_error(str(err)) log_error(str(err))
return None return None
@ -227,8 +255,8 @@ async def async_prepare_setup_platform(hass: core.HomeAssistant, config: Dict,
async def async_process_deps_reqs( async def async_process_deps_reqs(
hass: core.HomeAssistant, config: Dict, name: str, hass: core.HomeAssistant, config: Dict,
module: ModuleType) -> None: integration: loader.Integration) -> None:
"""Process all dependencies and requirements for a module. """Process all dependencies and requirements for a module.
Module is a Python module of either a component or platform. Module is a Python module of either a component or platform.
@ -237,24 +265,23 @@ async def async_process_deps_reqs(
if processed is None: if processed is None:
processed = hass.data[DATA_DEPS_REQS] = set() processed = hass.data[DATA_DEPS_REQS] = set()
elif name in processed: elif integration.domain in processed:
return return
if hasattr(module, 'DEPENDENCIES'): if integration.dependencies and not await _async_process_dependencies(
dep_success = await _async_process_dependencies( hass,
hass, config, name, module.DEPENDENCIES) # type: ignore config,
integration.domain,
if not dep_success: integration.dependencies
):
raise HomeAssistantError("Could not set up all dependencies.") raise HomeAssistantError("Could not set up all dependencies.")
if not hass.config.skip_pip and hasattr(module, 'REQUIREMENTS'): if (not hass.config.skip_pip and integration.requirements and
req_success = await requirements.async_process_requirements( not await requirements.async_process_requirements(
hass, name, module.REQUIREMENTS) # type: ignore hass, integration.domain, integration.requirements)):
if not req_success:
raise HomeAssistantError("Could not install all requirements.") raise HomeAssistantError("Could not install all requirements.")
processed.add(name) processed.add(integration.domain)
@core.callback @core.callback

View File

@ -111,6 +111,9 @@ geojson_client==0.3
# homeassistant.components.geo_rss_events # homeassistant.components.geo_rss_events
georss_generic_client==0.2 georss_generic_client==0.2
# homeassistant.components.google
google-api-python-client==1.6.4
# homeassistant.components.ffmpeg # homeassistant.components.ffmpeg
ha-ffmpeg==2.0 ha-ffmpeg==2.0
@ -138,6 +141,10 @@ homekit[IP]==0.13.0
# homeassistant.components.homematicip_cloud # homeassistant.components.homematicip_cloud
homematicip==0.10.6 homematicip==0.10.6
# homeassistant.components.google
# homeassistant.components.remember_the_milk
httplib2==0.10.3
# homeassistant.components.influxdb # homeassistant.components.influxdb
influxdb==5.2.0 influxdb==5.2.0
@ -165,6 +172,9 @@ mficlient==0.3.0
# homeassistant.components.trend # homeassistant.components.trend
numpy==1.16.2 numpy==1.16.2
# homeassistant.components.google
oauth2client==4.0.0
# homeassistant.components.mqtt # homeassistant.components.mqtt
# homeassistant.components.shiftr # homeassistant.components.shiftr
paho-mqtt==1.4.0 paho-mqtt==1.4.0

View File

@ -62,6 +62,7 @@ TEST_REQUIREMENTS = (
'foobot_async', 'foobot_async',
'geojson_client', 'geojson_client',
'georss_generic_client', 'georss_generic_client',
'google-api-python-client',
'gTTS-token', 'gTTS-token',
'ha-ffmpeg', 'ha-ffmpeg',
'hangups', 'hangups',
@ -74,6 +75,7 @@ TEST_REQUIREMENTS = (
'home-assistant-frontend', 'home-assistant-frontend',
'homekit[IP]', 'homekit[IP]',
'homematicip', 'homematicip',
'httplib2',
'influxdb', 'influxdb',
'jsonpath', 'jsonpath',
'libpurecool', 'libpurecool',
@ -82,6 +84,7 @@ TEST_REQUIREMENTS = (
'mbddns', 'mbddns',
'mficlient', 'mficlient',
'numpy', 'numpy',
'oauth2client',
'paho-mqtt', 'paho-mqtt',
'pexpect', 'pexpect',
'pilight', 'pilight',

View File

@ -906,11 +906,26 @@ def mock_integration(hass, module):
integration = loader.Integration( integration = loader.Integration(
hass, 'homeassisant.components.{}'.format(module.DOMAIN), hass, 'homeassisant.components.{}'.format(module.DOMAIN),
loader.manifest_from_legacy_module(module)) loader.manifest_from_legacy_module(module))
integration.get_component = lambda: module
# Backwards compat
loader.set_component(hass, module.DOMAIN, module)
_LOGGER.info("Adding mock integration: %s", module.DOMAIN)
hass.data.setdefault( hass.data.setdefault(
loader.DATA_INTEGRATIONS, {} loader.DATA_INTEGRATIONS, {}
)[module.DOMAIN] = integration )[module.DOMAIN] = integration
hass.data.setdefault(loader.DATA_KEY, {})[module.DOMAIN] = module
def mock_entity_platform(hass, platform_path, module):
"""Mock a entity platform.
platform_path is in form light.hue. Will create platform
hue.light.
"""
domain, platform_name = platform_path.split('.')
integration_cache = hass.data.setdefault(loader.DATA_KEY, {})
module_cache = hass.data.setdefault(loader.DATA_KEY, {})
if platform_name not in integration_cache:
mock_integration(hass, MockModule(platform_name))
_LOGGER.info("Adding mock integration platform: %s", platform_path)
module_cache["{}.{}".format(platform_name, domain)] = module

View File

@ -40,14 +40,13 @@ class TestDemoPlatform(unittest.TestCase):
assert setup_component(self.hass, geo_location.DOMAIN, CONFIG) assert setup_component(self.hass, geo_location.DOMAIN, CONFIG)
self.hass.block_till_done() self.hass.block_till_done()
# In this test, five geolocation entities have been # In this test, one zone and geolocation entities have been
# generated. # generated.
all_states = self.hass.states.all() all_states = self.hass.states.all()
print(all_states) assert len(all_states) == NUMBER_OF_DEMO_DEVICES + 1
assert len(all_states) == NUMBER_OF_DEMO_DEVICES
# Check a single device's attributes. # Check a single device's attributes.
state_first_entry = all_states[0] state_first_entry = all_states[1] # 0 is zone
assert abs( assert abs(
state_first_entry.attributes['latitude'] - state_first_entry.attributes['latitude'] -
self.hass.config.latitude self.hass.config.latitude
@ -64,5 +63,5 @@ class TestDemoPlatform(unittest.TestCase):
# Get all states again, ensure that the number of states is still # Get all states again, ensure that the number of states is still
# the same, but the lists are different. # the same, but the lists are different.
all_states_updated = self.hass.states.all() all_states_updated = self.hass.states.all()
assert len(all_states_updated) == NUMBER_OF_DEMO_DEVICES assert len(all_states_updated) == NUMBER_OF_DEMO_DEVICES + 1
assert all_states != all_states_updated assert all_states != all_states_updated

View File

@ -38,6 +38,7 @@ def demo_cleanup(hass):
pass pass
@pytest.mark.skip
@asyncio.coroutine @asyncio.coroutine
def test_if_demo_state_shows_by_default(hass, minimize_demo_platforms): def test_if_demo_state_shows_by_default(hass, minimize_demo_platforms):
"""Test if demo state shows if we give no configuration.""" """Test if demo state shows if we give no configuration."""
@ -46,6 +47,7 @@ def test_if_demo_state_shows_by_default(hass, minimize_demo_platforms):
assert hass.states.get('a.Demo_Mode') is not None assert hass.states.get('a.Demo_Mode') is not None
@pytest.mark.skip
@asyncio.coroutine @asyncio.coroutine
def test_hiding_demo_state(hass, minimize_demo_platforms): def test_hiding_demo_state(hass, minimize_demo_platforms):
"""Test if you can hide the demo card.""" """Test if you can hide the demo card."""
@ -55,6 +57,7 @@ def test_hiding_demo_state(hass, minimize_demo_platforms):
assert hass.states.get('a.Demo_Mode') is None assert hass.states.get('a.Demo_Mode') is None
@pytest.mark.skip
@asyncio.coroutine @asyncio.coroutine
def test_all_entities_can_be_loaded_over_json(hass): def test_all_entities_can_be_loaded_over_json(hass):
"""Test if you can hide the demo card.""" """Test if you can hide the demo card."""

View File

@ -19,12 +19,12 @@ from tests.components.light import common as common_light
def scanner(hass): def scanner(hass):
"""Initialize components.""" """Initialize components."""
scanner = loader.get_component( scanner = loader.get_component(
hass, 'device_tracker.test').get_scanner(None, None) hass, 'test.device_tracker').get_scanner(None, None)
scanner.reset() scanner.reset()
scanner.come_home('DEV1') scanner.come_home('DEV1')
loader.get_component(hass, 'light.test').init() loader.get_component(hass, 'test.light').init()
with patch( with patch(
'homeassistant.components.device_tracker.load_yaml_config_file', 'homeassistant.components.device_tracker.load_yaml_config_file',

View File

@ -192,7 +192,7 @@ async def test_discover_platform(mock_demo_setup_scanner, mock_see, hass):
async def test_update_stale(hass): async def test_update_stale(hass):
"""Test stalled update.""" """Test stalled update."""
scanner = get_component(hass, 'device_tracker.test').SCANNER scanner = get_component(hass, 'test.device_tracker').SCANNER
scanner.reset() scanner.reset()
scanner.come_home('DEV1') scanner.come_home('DEV1')
@ -256,7 +256,7 @@ async def test_device_hidden(hass, yaml_devices):
hide_if_away=True) hide_if_away=True)
device_tracker.update_config(yaml_devices, dev_id, device) device_tracker.update_config(yaml_devices, dev_id, device)
scanner = get_component(hass, 'device_tracker.test').SCANNER scanner = get_component(hass, 'test.device_tracker').SCANNER
scanner.reset() scanner.reset()
with assert_setup_component(1, device_tracker.DOMAIN): with assert_setup_component(1, device_tracker.DOMAIN):
@ -275,7 +275,7 @@ async def test_group_all_devices(hass, yaml_devices):
hide_if_away=True) hide_if_away=True)
device_tracker.update_config(yaml_devices, dev_id, device) device_tracker.update_config(yaml_devices, dev_id, device)
scanner = get_component(hass, 'device_tracker.test').SCANNER scanner = get_component(hass, 'test.device_tracker').SCANNER
scanner.reset() scanner.reset()
with assert_setup_component(1, device_tracker.DOMAIN): with assert_setup_component(1, device_tracker.DOMAIN):
@ -441,7 +441,7 @@ async def test_see_passive_zone_state(hass):
'zone': zone_info 'zone': zone_info
}) })
scanner = get_component(hass, 'device_tracker.test').SCANNER scanner = get_component(hass, 'test.device_tracker').SCANNER
scanner.reset() scanner.reset()
scanner.come_home('dev1') scanner.come_home('dev1')
@ -557,7 +557,7 @@ def test_bad_platform(hass):
async def test_adding_unknown_device_to_config(mock_device_tracker_conf, hass): async def test_adding_unknown_device_to_config(mock_device_tracker_conf, hass):
"""Test the adding of unknown devices to configuration file.""" """Test the adding of unknown devices to configuration file."""
scanner = get_component(hass, 'device_tracker.test').SCANNER scanner = get_component(hass, 'test.device_tracker').SCANNER
scanner.reset() scanner.reset()
scanner.come_home('DEV1') scanner.come_home('DEV1')

View File

@ -74,7 +74,7 @@ class TestSwitchFlux(unittest.TestCase):
def test_flux_when_switch_is_off(self): def test_flux_when_switch_is_off(self):
"""Test the flux switch when it is off.""" """Test the flux switch when it is off."""
platform = loader.get_component(self.hass, 'light.test') platform = loader.get_component(self.hass, 'test.light')
platform.init() platform.init()
assert setup_component(self.hass, light.DOMAIN, assert setup_component(self.hass, light.DOMAIN,
{light.DOMAIN: {CONF_PLATFORM: 'test'}}) {light.DOMAIN: {CONF_PLATFORM: 'test'}})
@ -114,7 +114,7 @@ class TestSwitchFlux(unittest.TestCase):
def test_flux_before_sunrise(self): def test_flux_before_sunrise(self):
"""Test the flux switch before sunrise.""" """Test the flux switch before sunrise."""
platform = loader.get_component(self.hass, 'light.test') platform = loader.get_component(self.hass, 'test.light')
platform.init() platform.init()
assert setup_component(self.hass, light.DOMAIN, assert setup_component(self.hass, light.DOMAIN,
{light.DOMAIN: {CONF_PLATFORM: 'test'}}) {light.DOMAIN: {CONF_PLATFORM: 'test'}})
@ -159,7 +159,7 @@ class TestSwitchFlux(unittest.TestCase):
# pylint: disable=invalid-name # pylint: disable=invalid-name
def test_flux_after_sunrise_before_sunset(self): def test_flux_after_sunrise_before_sunset(self):
"""Test the flux switch after sunrise and before sunset.""" """Test the flux switch after sunrise and before sunset."""
platform = loader.get_component(self.hass, 'light.test') platform = loader.get_component(self.hass, 'test.light')
platform.init() platform.init()
assert setup_component(self.hass, light.DOMAIN, assert setup_component(self.hass, light.DOMAIN,
{light.DOMAIN: {CONF_PLATFORM: 'test'}}) {light.DOMAIN: {CONF_PLATFORM: 'test'}})
@ -205,7 +205,7 @@ class TestSwitchFlux(unittest.TestCase):
# pylint: disable=invalid-name # pylint: disable=invalid-name
def test_flux_after_sunset_before_stop(self): def test_flux_after_sunset_before_stop(self):
"""Test the flux switch after sunset and before stop.""" """Test the flux switch after sunset and before stop."""
platform = loader.get_component(self.hass, 'light.test') platform = loader.get_component(self.hass, 'test.light')
platform.init() platform.init()
assert setup_component(self.hass, light.DOMAIN, assert setup_component(self.hass, light.DOMAIN,
{light.DOMAIN: {CONF_PLATFORM: 'test'}}) {light.DOMAIN: {CONF_PLATFORM: 'test'}})
@ -252,7 +252,7 @@ class TestSwitchFlux(unittest.TestCase):
# pylint: disable=invalid-name # pylint: disable=invalid-name
def test_flux_after_stop_before_sunrise(self): def test_flux_after_stop_before_sunrise(self):
"""Test the flux switch after stop and before sunrise.""" """Test the flux switch after stop and before sunrise."""
platform = loader.get_component(self.hass, 'light.test') platform = loader.get_component(self.hass, 'test.light')
platform.init() platform.init()
assert setup_component(self.hass, light.DOMAIN, assert setup_component(self.hass, light.DOMAIN,
{light.DOMAIN: {CONF_PLATFORM: 'test'}}) {light.DOMAIN: {CONF_PLATFORM: 'test'}})
@ -297,7 +297,7 @@ class TestSwitchFlux(unittest.TestCase):
# pylint: disable=invalid-name # pylint: disable=invalid-name
def test_flux_with_custom_start_stop_times(self): def test_flux_with_custom_start_stop_times(self):
"""Test the flux with custom start and stop times.""" """Test the flux with custom start and stop times."""
platform = loader.get_component(self.hass, 'light.test') platform = loader.get_component(self.hass, 'test.light')
platform.init() platform.init()
assert setup_component(self.hass, light.DOMAIN, assert setup_component(self.hass, light.DOMAIN,
{light.DOMAIN: {CONF_PLATFORM: 'test'}}) {light.DOMAIN: {CONF_PLATFORM: 'test'}})
@ -347,7 +347,7 @@ class TestSwitchFlux(unittest.TestCase):
This test has the stop_time on the next day (after midnight). This test has the stop_time on the next day (after midnight).
""" """
platform = loader.get_component(self.hass, 'light.test') platform = loader.get_component(self.hass, 'test.light')
platform.init() platform.init()
assert setup_component(self.hass, light.DOMAIN, assert setup_component(self.hass, light.DOMAIN,
{light.DOMAIN: {CONF_PLATFORM: 'test'}}) {light.DOMAIN: {CONF_PLATFORM: 'test'}})
@ -398,7 +398,7 @@ class TestSwitchFlux(unittest.TestCase):
This test has the stop_time on the next day (after midnight). This test has the stop_time on the next day (after midnight).
""" """
platform = loader.get_component(self.hass, 'light.test') platform = loader.get_component(self.hass, 'test.light')
platform.init() platform.init()
assert setup_component(self.hass, light.DOMAIN, assert setup_component(self.hass, light.DOMAIN,
{light.DOMAIN: {CONF_PLATFORM: 'test'}}) {light.DOMAIN: {CONF_PLATFORM: 'test'}})
@ -448,7 +448,7 @@ class TestSwitchFlux(unittest.TestCase):
This test has the stop_time on the next day (after midnight). This test has the stop_time on the next day (after midnight).
""" """
platform = loader.get_component(self.hass, 'light.test') platform = loader.get_component(self.hass, 'test.light')
platform.init() platform.init()
assert setup_component(self.hass, light.DOMAIN, assert setup_component(self.hass, light.DOMAIN,
{light.DOMAIN: {CONF_PLATFORM: 'test'}}) {light.DOMAIN: {CONF_PLATFORM: 'test'}})
@ -497,7 +497,7 @@ class TestSwitchFlux(unittest.TestCase):
This test has the stop_time on the next day (after midnight). This test has the stop_time on the next day (after midnight).
""" """
platform = loader.get_component(self.hass, 'light.test') platform = loader.get_component(self.hass, 'test.light')
platform.init() platform.init()
assert setup_component(self.hass, light.DOMAIN, assert setup_component(self.hass, light.DOMAIN,
{light.DOMAIN: {CONF_PLATFORM: 'test'}}) {light.DOMAIN: {CONF_PLATFORM: 'test'}})
@ -547,7 +547,7 @@ class TestSwitchFlux(unittest.TestCase):
This test has the stop_time on the next day (after midnight). This test has the stop_time on the next day (after midnight).
""" """
platform = loader.get_component(self.hass, 'light.test') platform = loader.get_component(self.hass, 'test.light')
platform.init() platform.init()
assert setup_component(self.hass, light.DOMAIN, assert setup_component(self.hass, light.DOMAIN,
{light.DOMAIN: {CONF_PLATFORM: 'test'}}) {light.DOMAIN: {CONF_PLATFORM: 'test'}})
@ -594,7 +594,7 @@ class TestSwitchFlux(unittest.TestCase):
# pylint: disable=invalid-name # pylint: disable=invalid-name
def test_flux_with_custom_colortemps(self): def test_flux_with_custom_colortemps(self):
"""Test the flux with custom start and stop colortemps.""" """Test the flux with custom start and stop colortemps."""
platform = loader.get_component(self.hass, 'light.test') platform = loader.get_component(self.hass, 'test.light')
platform.init() platform.init()
assert setup_component(self.hass, light.DOMAIN, assert setup_component(self.hass, light.DOMAIN,
{light.DOMAIN: {CONF_PLATFORM: 'test'}}) {light.DOMAIN: {CONF_PLATFORM: 'test'}})
@ -643,7 +643,7 @@ class TestSwitchFlux(unittest.TestCase):
# pylint: disable=invalid-name # pylint: disable=invalid-name
def test_flux_with_custom_brightness(self): def test_flux_with_custom_brightness(self):
"""Test the flux with custom start and stop colortemps.""" """Test the flux with custom start and stop colortemps."""
platform = loader.get_component(self.hass, 'light.test') platform = loader.get_component(self.hass, 'test.light')
platform.init() platform.init()
assert setup_component(self.hass, light.DOMAIN, assert setup_component(self.hass, light.DOMAIN,
{light.DOMAIN: {CONF_PLATFORM: 'test'}}) {light.DOMAIN: {CONF_PLATFORM: 'test'}})
@ -690,7 +690,7 @@ class TestSwitchFlux(unittest.TestCase):
def test_flux_with_multiple_lights(self): def test_flux_with_multiple_lights(self):
"""Test the flux switch with multiple light entities.""" """Test the flux switch with multiple light entities."""
platform = loader.get_component(self.hass, 'light.test') platform = loader.get_component(self.hass, 'test.light')
platform.init() platform.init()
assert setup_component(self.hass, light.DOMAIN, assert setup_component(self.hass, light.DOMAIN,
{light.DOMAIN: {CONF_PLATFORM: 'test'}}) {light.DOMAIN: {CONF_PLATFORM: 'test'}})
@ -758,7 +758,7 @@ class TestSwitchFlux(unittest.TestCase):
def test_flux_with_mired(self): def test_flux_with_mired(self):
"""Test the flux switch´s mode mired.""" """Test the flux switch´s mode mired."""
platform = loader.get_component(self.hass, 'light.test') platform = loader.get_component(self.hass, 'test.light')
platform.init() platform.init()
assert setup_component(self.hass, light.DOMAIN, assert setup_component(self.hass, light.DOMAIN,
{light.DOMAIN: {CONF_PLATFORM: 'test'}}) {light.DOMAIN: {CONF_PLATFORM: 'test'}})
@ -802,7 +802,7 @@ class TestSwitchFlux(unittest.TestCase):
def test_flux_with_rgb(self): def test_flux_with_rgb(self):
"""Test the flux switch´s mode rgb.""" """Test the flux switch´s mode rgb."""
platform = loader.get_component(self.hass, 'light.test') platform = loader.get_component(self.hass, 'test.light')
platform.init() platform.init()
assert setup_component(self.hass, light.DOMAIN, assert setup_component(self.hass, light.DOMAIN,
{light.DOMAIN: {CONF_PLATFORM: 'test'}}) {light.DOMAIN: {CONF_PLATFORM: 'test'}})

View File

@ -78,9 +78,9 @@ def test_frontend_and_static(mock_http_client, mock_onboarded):
# Test we can retrieve frontend.js # Test we can retrieve frontend.js
frontendjs = re.search( frontendjs = re.search(
r'(?P<app>\/frontend_es5\/app-[A-Za-z0-9]{8}.js)', text) r'(?P<app>\/frontend_es5\/app.[A-Za-z0-9]{8}.js)', text)
assert frontendjs is not None assert frontendjs is not None, text
resp = yield from mock_http_client.get(frontendjs.groups(0)[0]) resp = yield from mock_http_client.get(frontendjs.groups(0)[0])
assert resp.status == 200 assert resp.status == 200
assert 'public' in resp.headers.get('cache-control') assert 'public' in resp.headers.get('cache-control')

View File

@ -98,7 +98,7 @@ async def test_heater_input_boolean(hass, setup_comp_1):
async def test_heater_switch(hass, setup_comp_1): async def test_heater_switch(hass, setup_comp_1):
"""Test heater switching test switch.""" """Test heater switching test switch."""
platform = loader.get_component(hass, 'switch.test') platform = loader.get_component(hass, 'test.switch')
platform.init() platform.init()
switch_1 = platform.DEVICES[1] switch_1 = platform.DEVICES[1]
assert await async_setup_component(hass, switch.DOMAIN, {'switch': { assert await async_setup_component(hass, switch.DOMAIN, {'switch': {
@ -112,6 +112,7 @@ async def test_heater_switch(hass, setup_comp_1):
'target_sensor': ENT_SENSOR 'target_sensor': ENT_SENSOR
}}) }})
await hass.async_block_till_done()
assert STATE_OFF == \ assert STATE_OFF == \
hass.states.get(heater_switch).state hass.states.get(heater_switch).state

View File

@ -121,7 +121,7 @@ class TestLight(unittest.TestCase):
def test_services(self): def test_services(self):
"""Test the provided services.""" """Test the provided services."""
platform = loader.get_component(self.hass, 'light.test') platform = loader.get_component(self.hass, 'test.light')
platform.init() platform.init()
assert setup_component(self.hass, light.DOMAIN, assert setup_component(self.hass, light.DOMAIN,
@ -308,7 +308,7 @@ class TestLight(unittest.TestCase):
def test_broken_light_profiles(self): def test_broken_light_profiles(self):
"""Test light profiles.""" """Test light profiles."""
platform = loader.get_component(self.hass, 'light.test') platform = loader.get_component(self.hass, 'test.light')
platform.init() platform.init()
user_light_file = self.hass.config.path(light.LIGHT_PROFILES_FILE) user_light_file = self.hass.config.path(light.LIGHT_PROFILES_FILE)
@ -323,7 +323,7 @@ class TestLight(unittest.TestCase):
def test_light_profiles(self): def test_light_profiles(self):
"""Test light profiles.""" """Test light profiles."""
platform = loader.get_component(self.hass, 'light.test') platform = loader.get_component(self.hass, 'test.light')
platform.init() platform.init()
user_light_file = self.hass.config.path(light.LIGHT_PROFILES_FILE) user_light_file = self.hass.config.path(light.LIGHT_PROFILES_FILE)
@ -362,7 +362,7 @@ class TestLight(unittest.TestCase):
def test_default_profiles_group(self): def test_default_profiles_group(self):
"""Test default turn-on light profile for all lights.""" """Test default turn-on light profile for all lights."""
platform = loader.get_component(self.hass, 'light.test') platform = loader.get_component(self.hass, 'test.light')
platform.init() platform.init()
user_light_file = self.hass.config.path(light.LIGHT_PROFILES_FILE) user_light_file = self.hass.config.path(light.LIGHT_PROFILES_FILE)
@ -400,7 +400,7 @@ class TestLight(unittest.TestCase):
def test_default_profiles_light(self): def test_default_profiles_light(self):
"""Test default turn-on light profile for a specific light.""" """Test default turn-on light profile for a specific light."""
platform = loader.get_component(self.hass, 'light.test') platform = loader.get_component(self.hass, 'test.light')
platform.init() platform.init()
user_light_file = self.hass.config.path(light.LIGHT_PROFILES_FILE) user_light_file = self.hass.config.path(light.LIGHT_PROFILES_FILE)

View File

@ -85,7 +85,7 @@ class TestNX584SensorSetup(unittest.TestCase):
def _test_assert_graceful_fail(self, config): def _test_assert_graceful_fail(self, config):
"""Test the failing.""" """Test the failing."""
assert not setup_component( assert not setup_component(
self.hass, 'binary_sensor.nx584', config) self.hass, 'nx584', config)
def test_setup_bad_config(self): def test_setup_bad_config(self):
"""Test the setup with bad configuration.""" """Test the setup with bad configuration."""

View File

@ -18,7 +18,7 @@ class TestScene(unittest.TestCase):
def setUp(self): # pylint: disable=invalid-name def setUp(self): # pylint: disable=invalid-name
"""Set up things to be run when tests are started.""" """Set up things to be run when tests are started."""
self.hass = get_test_home_assistant() self.hass = get_test_home_assistant()
test_light = loader.get_component(self.hass, 'light.test') test_light = loader.get_component(self.hass, 'test.light')
test_light.init() test_light.init()
assert setup_component(self.hass, light.DOMAIN, { assert setup_component(self.hass, light.DOMAIN, {

View File

@ -18,7 +18,7 @@ class TestSwitch(unittest.TestCase):
def setUp(self): def setUp(self):
"""Set up things to be run when tests are started.""" """Set up things to be run when tests are started."""
self.hass = get_test_home_assistant() self.hass = get_test_home_assistant()
platform = loader.get_component(self.hass, 'switch.test') platform = loader.get_component(self.hass, 'test.switch')
platform.init() platform.init()
# Switch 1 is ON, switch 2 is OFF # Switch 1 is ON, switch 2 is OFF
self.switch_1, self.switch_2, self.switch_3 = \ self.switch_1, self.switch_2, self.switch_3 = \
@ -77,7 +77,7 @@ class TestSwitch(unittest.TestCase):
def test_setup_two_platforms(self): def test_setup_two_platforms(self):
"""Test with bad configuration.""" """Test with bad configuration."""
# Test if switch component returns 0 switches # Test if switch component returns 0 switches
test_platform = loader.get_component(self.hass, 'switch.test') test_platform = loader.get_component(self.hass, 'test.switch')
test_platform.init(True) test_platform.init(True)
loader.set_component(self.hass, 'switch.test2', test_platform) loader.set_component(self.hass, 'switch.test2', test_platform)
@ -99,6 +99,8 @@ async def test_switch_context(hass, hass_admin_user):
} }
}) })
await hass.async_block_till_done()
state = hass.states.get('switch.ac') state = hass.states.get('switch.ac')
assert state is not None assert state is not None

View File

@ -132,10 +132,14 @@ class TestHelpersDiscovery:
self.hass, 'test_component', self.hass, 'test_component',
MockModule('test_component', setup=component_setup)) MockModule('test_component', setup=component_setup))
# dependencies are only set in component level
# since we are using manifest to hold them
loader.set_component( loader.set_component(
self.hass, 'switch.test_circular', self.hass, 'test_circular',
MockPlatform(setup_platform, MockModule('test_circular', dependencies=['test_component']))
dependencies=['test_component'])) loader.set_component(
self.hass, 'test_circular.switch',
MockPlatform(setup_platform))
setup.setup_component(self.hass, 'test_component', { setup.setup_component(self.hass, 'test_component', {
'test_component': None, 'test_component': None,

View File

@ -21,7 +21,8 @@ import homeassistant.util.dt as dt_util
from tests.common import ( from tests.common import (
get_test_home_assistant, MockPlatform, MockModule, mock_coro, get_test_home_assistant, MockPlatform, MockModule, mock_coro,
async_fire_time_changed, MockEntity, MockConfigEntry) async_fire_time_changed, MockEntity, MockConfigEntry,
mock_entity_platform, mock_integration)
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DOMAIN = "test_domain" DOMAIN = "test_domain"
@ -74,11 +75,14 @@ class TestHelpersEntityComponent(unittest.TestCase):
"""Test the loading of the platforms.""" """Test the loading of the platforms."""
component_setup = Mock(return_value=True) component_setup = Mock(return_value=True)
platform_setup = Mock(return_value=None) platform_setup = Mock(return_value=None)
loader.set_component(
self.hass, 'test_component', mock_integration(self.hass,
MockModule('test_component', setup=component_setup)) MockModule('test_component', setup=component_setup))
loader.set_component(self.hass, 'test_domain.mod2', # mock the dependencies
MockPlatform(platform_setup, ['test_component'])) mock_integration(self.hass,
MockModule('mod2', dependencies=['test_component']))
mock_entity_platform(self.hass, 'test_domain.mod2',
MockPlatform(platform_setup))
component = EntityComponent(_LOGGER, DOMAIN, self.hass) component = EntityComponent(_LOGGER, DOMAIN, self.hass)
@ -100,9 +104,9 @@ class TestHelpersEntityComponent(unittest.TestCase):
platform1_setup = Mock(side_effect=Exception('Broken')) platform1_setup = Mock(side_effect=Exception('Broken'))
platform2_setup = Mock(return_value=None) platform2_setup = Mock(return_value=None)
loader.set_component(self.hass, 'test_domain.mod1', mock_entity_platform(self.hass, 'test_domain.mod1',
MockPlatform(platform1_setup)) MockPlatform(platform1_setup))
loader.set_component(self.hass, 'test_domain.mod2', mock_entity_platform(self.hass, 'test_domain.mod2',
MockPlatform(platform2_setup)) MockPlatform(platform2_setup))
component = EntityComponent(_LOGGER, DOMAIN, self.hass) component = EntityComponent(_LOGGER, DOMAIN, self.hass)
@ -147,7 +151,7 @@ class TestHelpersEntityComponent(unittest.TestCase):
"""Test the platform setup.""" """Test the platform setup."""
add_entities([MockEntity(should_poll=True)]) add_entities([MockEntity(should_poll=True)])
loader.set_component(self.hass, 'test_domain.platform', mock_entity_platform(self.hass, 'test_domain.platform',
MockPlatform(platform_setup)) MockPlatform(platform_setup))
component = EntityComponent(_LOGGER, DOMAIN, self.hass) component = EntityComponent(_LOGGER, DOMAIN, self.hass)
@ -174,7 +178,7 @@ class TestHelpersEntityComponent(unittest.TestCase):
platform = MockPlatform(platform_setup) platform = MockPlatform(platform_setup)
loader.set_component(self.hass, 'test_domain.platform', platform) mock_entity_platform(self.hass, 'test_domain.platform', platform)
component = EntityComponent(_LOGGER, DOMAIN, self.hass) component = EntityComponent(_LOGGER, DOMAIN, self.hass)
@ -222,7 +226,9 @@ def test_platform_not_ready(hass):
"""Test that we retry when platform not ready.""" """Test that we retry when platform not ready."""
platform1_setup = Mock(side_effect=[PlatformNotReady, PlatformNotReady, platform1_setup = Mock(side_effect=[PlatformNotReady, PlatformNotReady,
None]) None])
loader.set_component(hass, 'test_domain.mod1', loader.set_component(hass, 'mod1',
MockModule('mod1'))
loader.set_component(hass, 'mod1.test_domain',
MockPlatform(platform1_setup)) MockPlatform(platform1_setup))
component = EntityComponent(_LOGGER, DOMAIN, hass) component = EntityComponent(_LOGGER, DOMAIN, hass)
@ -320,17 +326,15 @@ def test_setup_dependencies_platform(hass):
We're explictely testing that we process dependencies even if a component We're explictely testing that we process dependencies even if a component
with the same name has already been loaded. with the same name has already been loaded.
""" """
loader.set_component(hass, 'test_component', MockModule('test_component')) loader.set_component(hass, 'test_component',
MockModule('test_component',
dependencies=['test_component2']))
loader.set_component(hass, 'test_component2', loader.set_component(hass, 'test_component2',
MockModule('test_component2')) MockModule('test_component2'))
loader.set_component( loader.set_component(hass, 'test_component.test_domain', MockPlatform())
hass, 'test_component.test_domain',
MockPlatform(dependencies=['test_component', 'test_component2']))
component = EntityComponent(_LOGGER, DOMAIN, hass) component = EntityComponent(_LOGGER, DOMAIN, hass)
yield from async_setup_component(hass, 'test_component', {})
yield from component.async_setup({ yield from component.async_setup({
DOMAIN: { DOMAIN: {
'platform': 'test_component', 'platform': 'test_component',
@ -345,7 +349,7 @@ def test_setup_dependencies_platform(hass):
async def test_setup_entry(hass): async def test_setup_entry(hass):
"""Test setup entry calls async_setup_entry on platform.""" """Test setup entry calls async_setup_entry on platform."""
mock_setup_entry = Mock(return_value=mock_coro(True)) mock_setup_entry = Mock(return_value=mock_coro(True))
loader.set_component( mock_entity_platform(
hass, 'test_domain.entry_domain', hass, 'test_domain.entry_domain',
MockPlatform(async_setup_entry=mock_setup_entry, MockPlatform(async_setup_entry=mock_setup_entry,
scan_interval=timedelta(seconds=5))) scan_interval=timedelta(seconds=5)))
@ -374,7 +378,7 @@ async def test_setup_entry_platform_not_exist(hass):
async def test_setup_entry_fails_duplicate(hass): async def test_setup_entry_fails_duplicate(hass):
"""Test we don't allow setting up a config entry twice.""" """Test we don't allow setting up a config entry twice."""
mock_setup_entry = Mock(return_value=mock_coro(True)) mock_setup_entry = Mock(return_value=mock_coro(True))
loader.set_component( mock_entity_platform(
hass, 'test_domain.entry_domain', hass, 'test_domain.entry_domain',
MockPlatform(async_setup_entry=mock_setup_entry)) MockPlatform(async_setup_entry=mock_setup_entry))
@ -390,7 +394,7 @@ async def test_setup_entry_fails_duplicate(hass):
async def test_unload_entry_resets_platform(hass): async def test_unload_entry_resets_platform(hass):
"""Test unloading an entry removes all entities.""" """Test unloading an entry removes all entities."""
mock_setup_entry = Mock(return_value=mock_coro(True)) mock_setup_entry = Mock(return_value=mock_coro(True))
loader.set_component( mock_entity_platform(
hass, 'test_domain.entry_domain', hass, 'test_domain.entry_domain',
MockPlatform(async_setup_entry=mock_setup_entry)) MockPlatform(async_setup_entry=mock_setup_entry))

View File

@ -8,7 +8,6 @@ from datetime import timedelta
import pytest import pytest
from homeassistant.exceptions import PlatformNotReady from homeassistant.exceptions import PlatformNotReady
import homeassistant.loader as loader
from homeassistant.helpers.entity import generate_entity_id from homeassistant.helpers.entity import generate_entity_id
from homeassistant.helpers.entity_component import ( from homeassistant.helpers.entity_component import (
EntityComponent, DEFAULT_SCAN_INTERVAL) EntityComponent, DEFAULT_SCAN_INTERVAL)
@ -18,7 +17,7 @@ import homeassistant.util.dt as dt_util
from tests.common import ( from tests.common import (
get_test_home_assistant, MockPlatform, fire_time_changed, mock_registry, get_test_home_assistant, MockPlatform, fire_time_changed, mock_registry,
MockEntity, MockEntityPlatform, MockConfigEntry) MockEntity, MockEntityPlatform, MockConfigEntry, mock_entity_platform)
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DOMAIN = "test_domain" DOMAIN = "test_domain"
@ -149,7 +148,7 @@ class TestHelpersEntityPlatform(unittest.TestCase):
platform = MockPlatform(platform_setup) platform = MockPlatform(platform_setup)
platform.SCAN_INTERVAL = timedelta(seconds=30) platform.SCAN_INTERVAL = timedelta(seconds=30)
loader.set_component(self.hass, 'test_domain.platform', platform) mock_entity_platform(self.hass, 'test_domain.platform', platform)
component = EntityComponent(_LOGGER, DOMAIN, self.hass) component = EntityComponent(_LOGGER, DOMAIN, self.hass)
@ -186,7 +185,7 @@ def test_platform_warn_slow_setup(hass):
"""Warn we log when platform setup takes a long time.""" """Warn we log when platform setup takes a long time."""
platform = MockPlatform() platform = MockPlatform()
loader.set_component(hass, 'test_domain.platform', platform) mock_entity_platform(hass, 'test_domain.platform', platform)
component = EntityComponent(_LOGGER, DOMAIN, hass) component = EntityComponent(_LOGGER, DOMAIN, hass)
@ -199,7 +198,9 @@ def test_platform_warn_slow_setup(hass):
}) })
assert mock_call.called assert mock_call.called
timeout, logger_method = mock_call.mock_calls[0][1][:2] # mock_calls[0] is the warning message for component setup
# mock_calls[3] is the warning message for platform setup
timeout, logger_method = mock_call.mock_calls[3][1][:2]
assert timeout == entity_platform.SLOW_SETUP_WARNING assert timeout == entity_platform.SLOW_SETUP_WARNING
assert logger_method == _LOGGER.warning assert logger_method == _LOGGER.warning
@ -220,7 +221,7 @@ def test_platform_error_slow_setup(hass, caplog):
platform = MockPlatform(async_setup_platform=setup_platform) platform = MockPlatform(async_setup_platform=setup_platform)
component = EntityComponent(_LOGGER, DOMAIN, hass) component = EntityComponent(_LOGGER, DOMAIN, hass)
loader.set_component(hass, 'test_domain.test_platform', platform) mock_entity_platform(hass, 'test_domain.test_platform', platform)
yield from component.async_setup({ yield from component.async_setup({
DOMAIN: { DOMAIN: {
'platform': 'test_platform', 'platform': 'test_platform',
@ -255,7 +256,7 @@ async def test_parallel_updates_async_platform(hass):
"""Test async platform does not have parallel_updates limit by default.""" """Test async platform does not have parallel_updates limit by default."""
platform = MockPlatform() platform = MockPlatform()
loader.set_component(hass, 'test_domain.platform', platform) mock_entity_platform(hass, 'test_domain.platform', platform)
component = EntityComponent(_LOGGER, DOMAIN, hass) component = EntityComponent(_LOGGER, DOMAIN, hass)
component._platforms = {} component._platforms = {}
@ -285,7 +286,7 @@ async def test_parallel_updates_async_platform_with_constant(hass):
platform = MockPlatform() platform = MockPlatform()
platform.PARALLEL_UPDATES = 2 platform.PARALLEL_UPDATES = 2
loader.set_component(hass, 'test_domain.platform', platform) mock_entity_platform(hass, 'test_domain.platform', platform)
component = EntityComponent(_LOGGER, DOMAIN, hass) component = EntityComponent(_LOGGER, DOMAIN, hass)
component._platforms = {} component._platforms = {}
@ -316,7 +317,7 @@ async def test_parallel_updates_sync_platform(hass):
"""Test sync platform parallel_updates default set to 1.""" """Test sync platform parallel_updates default set to 1."""
platform = MockPlatform() platform = MockPlatform()
loader.set_component(hass, 'test_domain.platform', platform) mock_entity_platform(hass, 'test_domain.platform', platform)
component = EntityComponent(_LOGGER, DOMAIN, hass) component = EntityComponent(_LOGGER, DOMAIN, hass)
component._platforms = {} component._platforms = {}
@ -347,7 +348,7 @@ async def test_parallel_updates_sync_platform_with_constant(hass):
platform = MockPlatform() platform = MockPlatform()
platform.PARALLEL_UPDATES = 2 platform.PARALLEL_UPDATES = 2
loader.set_component(hass, 'test_domain.platform', platform) mock_entity_platform(hass, 'test_domain.platform', platform)
component = EntityComponent(_LOGGER, DOMAIN, hass) component = EntityComponent(_LOGGER, DOMAIN, hass)
component._platforms = {} component._platforms = {}

View File

@ -54,7 +54,7 @@ async def test_component_translation_file(hass):
assert path.normpath(translation.component_translation_file( assert path.normpath(translation.component_translation_file(
hass, 'switch.test', 'en')) == path.normpath(hass.config.path( hass, 'switch.test', 'en')) == path.normpath(hass.config.path(
'custom_components', 'switch', '.translations', 'test.en.json')) 'custom_components', 'test', '.translations', 'switch.en.json'))
assert path.normpath(translation.component_translation_file( assert path.normpath(translation.component_translation_file(
hass, 'switch.test_embedded', 'en')) == path.normpath(hass.config.path( hass, 'switch.test_embedded', 'en')) == path.normpath(hass.config.path(
@ -74,9 +74,9 @@ def test_load_translations_files(hass):
"""Test the load translation files function.""" """Test the load translation files function."""
# Test one valid and one invalid file # Test one valid and one invalid file
file1 = hass.config.path( file1 = hass.config.path(
'custom_components', 'switch', '.translations', 'test.en.json') 'custom_components', 'test', '.translations', 'switch.en.json')
file2 = hass.config.path( file2 = hass.config.path(
'custom_components', 'switch', '.translations', 'invalid.json') 'custom_components', 'test', '.translations', 'invalid.json')
assert translation.load_translations_files({ assert translation.load_translations_files({
'switch.test': file1, 'switch.test': file1,
'invalid': file2 'invalid': file2

View File

@ -13,16 +13,23 @@ from homeassistant.util import dt
from tests.common import ( from tests.common import (
MockModule, mock_coro, MockConfigEntry, async_fire_time_changed, MockModule, mock_coro, MockConfigEntry, async_fire_time_changed,
MockPlatform, MockEntity) MockPlatform, MockEntity, mock_integration, mock_entity_platform)
@config_entries.HANDLERS.register('test') @pytest.fixture(autouse=True)
@config_entries.HANDLERS.register('comp') def mock_handlers():
class MockFlowHandler(config_entries.ConfigFlow): """Mock config flows."""
class MockFlowHandler(config_entries.ConfigFlow):
"""Define a mock flow handler.""" """Define a mock flow handler."""
VERSION = 1 VERSION = 1
with patch.dict(config_entries.HANDLERS, {
'comp': MockFlowHandler,
'test': MockFlowHandler,
}):
yield
@pytest.fixture @pytest.fixture
def manager(hass): def manager(hass):
@ -185,23 +192,27 @@ async def test_remove_entry(hass, manager):
"""Mock setting up platform.""" """Mock setting up platform."""
async_add_entities([entity]) async_add_entities([entity])
loader.set_component(hass, 'test', MockModule( mock_integration(hass, MockModule(
'test', 'test',
async_setup_entry=mock_setup_entry, async_setup_entry=mock_setup_entry,
async_unload_entry=mock_unload_entry, async_unload_entry=mock_unload_entry,
async_remove_entry=mock_remove_entry async_remove_entry=mock_remove_entry
)) ))
loader.set_component( mock_entity_platform(
hass, 'test.light', hass, 'light.test',
MockPlatform(async_setup_entry=mock_setup_entry_platform)) MockPlatform(async_setup_entry=mock_setup_entry_platform))
MockConfigEntry(domain='test', entry_id='test1').add_to_manager(manager) MockConfigEntry(
domain='test_other', entry_id='test1'
).add_to_manager(manager)
entry = MockConfigEntry( entry = MockConfigEntry(
domain='test', domain='test',
entry_id='test2', entry_id='test2',
) )
entry.add_to_manager(manager) entry.add_to_manager(manager)
MockConfigEntry(domain='test', entry_id='test3').add_to_manager(manager) MockConfigEntry(
domain='test_other', entry_id='test3'
).add_to_manager(manager)
# Check all config entries exist # Check all config entries exist
assert [item.entry_id for item in manager.async_entries()] == \ assert [item.entry_id for item in manager.async_entries()] == \

View File

@ -1,6 +1,4 @@
"""Test to verify that we can load components.""" """Test to verify that we can load components."""
import asyncio
import pytest import pytest
import homeassistant.loader as loader import homeassistant.loader as loader
@ -63,20 +61,18 @@ def test_component_loader_non_existing(hass):
components.non_existing components.non_existing
@asyncio.coroutine async def test_component_wrapper(hass):
def test_component_wrapper(hass):
"""Test component wrapper.""" """Test component wrapper."""
calls = async_mock_service(hass, 'persistent_notification', 'create') calls = async_mock_service(hass, 'persistent_notification', 'create')
components = loader.Components(hass) components = loader.Components(hass)
components.persistent_notification.async_create('message') components.persistent_notification.async_create('message')
yield from hass.async_block_till_done() await hass.async_block_till_done()
assert len(calls) == 1 assert len(calls) == 1
@asyncio.coroutine async def test_helpers_wrapper(hass):
def test_helpers_wrapper(hass):
"""Test helpers wrapper.""" """Test helpers wrapper."""
helpers = loader.Helpers(hass) helpers = loader.Helpers(hass)
@ -88,8 +84,8 @@ def test_helpers_wrapper(hass):
helpers.discovery.async_listen('service_name', discovery_callback) helpers.discovery.async_listen('service_name', discovery_callback)
yield from helpers.discovery.async_discover('service_name', 'hello') await helpers.discovery.async_discover('service_name', 'hello')
yield from hass.async_block_till_done() await hass.async_block_till_done()
assert result == ['hello'] assert result == ['hello']
@ -104,9 +100,9 @@ async def test_custom_component_name(hass):
assert comp.__name__ == 'custom_components.test_package' assert comp.__name__ == 'custom_components.test_package'
assert comp.__package__ == 'custom_components.test_package' assert comp.__package__ == 'custom_components.test_package'
comp = loader.get_component(hass, 'light.test') comp = loader.get_component(hass, 'test.light')
assert comp.__name__ == 'custom_components.light.test' assert comp.__name__ == 'custom_components.test.light'
assert comp.__package__ == 'custom_components.light' assert comp.__package__ == 'custom_components.test'
# Test custom components is mounted # Test custom components is mounted
from custom_components.test_package import TEST from custom_components.test_package import TEST
@ -119,8 +115,8 @@ async def test_log_warning_custom_component(hass, caplog):
assert \ assert \
'You are using a custom component for test_standalone' in caplog.text 'You are using a custom component for test_standalone' in caplog.text
loader.get_component(hass, 'light.test') loader.get_component(hass, 'test.light')
assert 'You are using a custom component for light.test' in caplog.text assert 'You are using a custom component for test.light' in caplog.text
async def test_get_platform(hass, caplog): async def test_get_platform(hass, caplog):
@ -132,8 +128,8 @@ async def test_get_platform(hass, caplog):
caplog.clear() caplog.clear()
legacy_platform = loader.get_platform(hass, 'switch', 'test') legacy_platform = loader.get_platform(hass, 'switch', 'test_legacy')
assert legacy_platform.__name__ == 'custom_components.switch.test' assert legacy_platform.__name__ == 'custom_components.switch.test_legacy'
assert 'Integrations need to be in their own folder.' in caplog.text assert 'Integrations need to be in their own folder.' in caplog.text

View File

@ -20,7 +20,8 @@ from homeassistant.helpers import discovery
from tests.common import \ from tests.common import \
get_test_home_assistant, MockModule, MockPlatform, \ get_test_home_assistant, MockModule, MockPlatform, \
assert_setup_component, get_test_config_dir, mock_integration assert_setup_component, get_test_config_dir, mock_integration, \
mock_entity_platform
ORIG_TIMEZONE = dt_util.DEFAULT_TIME_ZONE ORIG_TIMEZONE = dt_util.DEFAULT_TIME_ZONE
VERSION_PATH = os.path.join(get_test_config_dir(), config_util.VERSION_FILE) VERSION_PATH = os.path.join(get_test_config_dir(), config_util.VERSION_FILE)
@ -50,9 +51,9 @@ class TestSetup:
'hello': str 'hello': str
} }
}, required=True) }, required=True)
loader.set_component( mock_integration(
self.hass, self.hass,
'comp_conf', MockModule('comp_conf', config_schema=config_schema)) MockModule('comp_conf', config_schema=config_schema))
with assert_setup_component(0): with assert_setup_component(0):
assert not setup.setup_component(self.hass, 'comp_conf', {}) assert not setup.setup_component(self.hass, 'comp_conf', {})
@ -97,17 +98,15 @@ class TestSetup:
}) })
platform_schema_base = PLATFORM_SCHEMA_BASE.extend({ platform_schema_base = PLATFORM_SCHEMA_BASE.extend({
}) })
loader.set_component( mock_integration(
self.hass, self.hass,
'platform_conf',
MockModule('platform_conf', MockModule('platform_conf',
platform_schema_base=platform_schema_base)) platform_schema_base=platform_schema_base),
)
loader.set_component( mock_entity_platform(
self.hass, self.hass,
'platform_conf.whatever', 'platform_conf.whatever',
MockPlatform('whatever', MockPlatform(platform_schema=platform_schema))
platform_schema=platform_schema))
with assert_setup_component(1): with assert_setup_component(1):
assert setup.setup_component(self.hass, 'platform_conf', { assert setup.setup_component(self.hass, 'platform_conf', {
@ -195,14 +194,13 @@ class TestSetup:
platform_schema_base = PLATFORM_SCHEMA_BASE.extend({ platform_schema_base = PLATFORM_SCHEMA_BASE.extend({
'hello': 'world', 'hello': 'world',
}) })
loader.set_component( mock_integration(
self.hass, self.hass,
'platform_conf',
MockModule('platform_conf', MockModule('platform_conf',
platform_schema=platform_schema, platform_schema=platform_schema,
platform_schema_base=platform_schema_base)) platform_schema_base=platform_schema_base))
loader.set_component( mock_entity_platform(
self.hass, self.hass,
'platform_conf.whatever', 'platform_conf.whatever',
MockPlatform('whatever', MockPlatform('whatever',
@ -249,13 +247,12 @@ class TestSetup:
'cheers': str, 'cheers': str,
'hello': 'world', 'hello': 'world',
}) })
loader.set_component( mock_integration(
self.hass, self.hass,
'platform_conf',
MockModule('platform_conf', MockModule('platform_conf',
platform_schema=component_schema)) platform_schema=component_schema))
loader.set_component( mock_entity_platform(
self.hass, self.hass,
'platform_conf.whatever', 'platform_conf.whatever',
MockPlatform('whatever', MockPlatform('whatever',
@ -296,17 +293,15 @@ class TestSetup:
"""Test entity_namespace in PLATFORM_SCHEMA.""" """Test entity_namespace in PLATFORM_SCHEMA."""
component_schema = PLATFORM_SCHEMA_BASE component_schema = PLATFORM_SCHEMA_BASE
platform_schema = PLATFORM_SCHEMA platform_schema = PLATFORM_SCHEMA
loader.set_component( mock_integration(
self.hass, self.hass,
'platform_conf',
MockModule('platform_conf', MockModule('platform_conf',
platform_schema_base=component_schema)) platform_schema_base=component_schema))
loader.set_component( mock_entity_platform(
self.hass, self.hass,
'platform_conf.whatever', 'platform_conf.whatever',
MockPlatform('whatever', MockPlatform(platform_schema=platform_schema))
platform_schema=platform_schema))
with assert_setup_component(1): with assert_setup_component(1):
assert setup.setup_component(self.hass, 'platform_conf', { assert setup.setup_component(self.hass, 'platform_conf', {
@ -322,14 +317,15 @@ class TestSetup:
def test_component_not_found(self): def test_component_not_found(self):
"""setup_component should not crash if component doesn't exist.""" """setup_component should not crash if component doesn't exist."""
assert not setup.setup_component(self.hass, 'non_existing') assert setup.setup_component(self.hass, 'non_existing') is False
def test_component_not_double_initialized(self): def test_component_not_double_initialized(self):
"""Test we do not set up a component twice.""" """Test we do not set up a component twice."""
mock_setup = mock.MagicMock(return_value=True) mock_setup = mock.MagicMock(return_value=True)
loader.set_component( mock_integration(
self.hass, 'comp', MockModule('comp', setup=mock_setup)) self.hass,
MockModule('comp', setup=mock_setup))
assert setup.setup_component(self.hass, 'comp') assert setup.setup_component(self.hass, 'comp')
assert mock_setup.called assert mock_setup.called
@ -344,9 +340,9 @@ class TestSetup:
def test_component_not_installed_if_requirement_fails(self, mock_install): def test_component_not_installed_if_requirement_fails(self, mock_install):
"""Component setup should fail if requirement can't install.""" """Component setup should fail if requirement can't install."""
self.hass.config.skip_pip = False self.hass.config.skip_pip = False
loader.set_component( mock_integration(
self.hass, self.hass,
'comp', MockModule('comp', requirements=['package==0.0.1'])) MockModule('comp', requirements=['package==0.0.1']))
assert not setup.setup_component(self.hass, 'comp') assert not setup.setup_component(self.hass, 'comp')
assert 'comp' not in self.hass.config.components assert 'comp' not in self.hass.config.components
@ -360,9 +356,9 @@ class TestSetup:
"""Tracking Setup.""" """Tracking Setup."""
result.append(1) result.append(1)
loader.set_component( mock_integration(
self.hass, self.hass,
'comp', MockModule('comp', async_setup=async_setup)) MockModule('comp', async_setup=async_setup))
def setup_component(): def setup_component():
"""Set up the component.""" """Set up the component."""
@ -393,8 +389,8 @@ class TestSetup:
def test_component_failing_setup(self): def test_component_failing_setup(self):
"""Test component that fails setup.""" """Test component that fails setup."""
loader.set_component( mock_integration(
self.hass, 'comp', self.hass,
MockModule('comp', setup=lambda hass, config: False)) MockModule('comp', setup=lambda hass, config: False))
assert not setup.setup_component(self.hass, 'comp', {}) assert not setup.setup_component(self.hass, 'comp', {})
@ -406,8 +402,8 @@ class TestSetup:
"""Raise exception.""" """Raise exception."""
raise Exception('fail!') raise Exception('fail!')
loader.set_component( mock_integration(self.hass,
self.hass, 'comp', MockModule('comp', setup=exception_setup)) MockModule('comp', setup=exception_setup))
assert not setup.setup_component(self.hass, 'comp', {}) assert not setup.setup_component(self.hass, 'comp', {})
assert 'comp' not in self.hass.config.components assert 'comp' not in self.hass.config.components
@ -420,12 +416,18 @@ class TestSetup:
return True return True
raise Exception('Config not passed in: {}'.format(config)) raise Exception('Config not passed in: {}'.format(config))
loader.set_component( platform = MockPlatform()
self.hass, 'comp_a',
MockModule('comp_a', setup=config_check_setup))
loader.set_component( mock_integration(self.hass,
self.hass, 'switch.platform_a', MockPlatform('comp_b', ['comp_a'])) MockModule('comp_a', setup=config_check_setup))
mock_integration(
self.hass,
MockModule('platform_a',
setup=config_check_setup,
dependencies=['comp_a']),
)
mock_entity_platform(self.hass, 'switch.platform_a', platform)
setup.setup_component(self.hass, 'switch', { setup.setup_component(self.hass, 'switch', {
'comp_a': { 'comp_a': {
@ -445,7 +447,7 @@ class TestSetup:
mock_setup = mock.MagicMock(spec_set=True) mock_setup = mock.MagicMock(spec_set=True)
loader.set_component( mock_entity_platform(
self.hass, self.hass,
'switch.platform_a', 'switch.platform_a',
MockPlatform(platform_schema=platform_schema, MockPlatform(platform_schema=platform_schema,
@ -476,7 +478,7 @@ class TestSetup:
self.hass.data.pop(setup.DATA_SETUP) self.hass.data.pop(setup.DATA_SETUP)
self.hass.config.components.remove('switch') self.hass.config.components.remove('switch')
with assert_setup_component(1): with assert_setup_component(1, 'switch'):
assert setup.setup_component(self.hass, 'switch', { assert setup.setup_component(self.hass, 'switch', {
'switch': { 'switch': {
'platform': 'platform_a', 'platform': 'platform_a',
@ -487,9 +489,8 @@ class TestSetup:
def test_disable_component_if_invalid_return(self): def test_disable_component_if_invalid_return(self):
"""Test disabling component if invalid return.""" """Test disabling component if invalid return."""
loader.set_component( mock_integration(
self.hass, self.hass,
'disabled_component',
MockModule('disabled_component', setup=lambda hass, config: None)) MockModule('disabled_component', setup=lambda hass, config: None))
assert not setup.setup_component(self.hass, 'disabled_component') assert not setup.setup_component(self.hass, 'disabled_component')
@ -497,9 +498,8 @@ class TestSetup:
assert 'disabled_component' not in self.hass.config.components assert 'disabled_component' not in self.hass.config.components
self.hass.data.pop(setup.DATA_SETUP) self.hass.data.pop(setup.DATA_SETUP)
loader.set_component( mock_integration(
self.hass, self.hass,
'disabled_component',
MockModule('disabled_component', setup=lambda hass, config: False)) MockModule('disabled_component', setup=lambda hass, config: False))
assert not setup.setup_component(self.hass, 'disabled_component') assert not setup.setup_component(self.hass, 'disabled_component')
@ -508,9 +508,8 @@ class TestSetup:
assert 'disabled_component' not in self.hass.config.components assert 'disabled_component' not in self.hass.config.components
self.hass.data.pop(setup.DATA_SETUP) self.hass.data.pop(setup.DATA_SETUP)
loader.set_component( mock_integration(
self.hass, self.hass,
'disabled_component',
MockModule('disabled_component', setup=lambda hass, config: True)) MockModule('disabled_component', setup=lambda hass, config: True))
assert setup.setup_component(self.hass, 'disabled_component') assert setup.setup_component(self.hass, 'disabled_component')
@ -535,19 +534,16 @@ class TestSetup:
call_order.append(1) call_order.append(1)
return True return True
loader.set_component( mock_integration(
self.hass, self.hass,
'test_component1',
MockModule('test_component1', setup=component1_setup)) MockModule('test_component1', setup=component1_setup))
loader.set_component( mock_integration(
self.hass, self.hass,
'test_component2',
MockModule('test_component2', setup=component_track_setup)) MockModule('test_component2', setup=component_track_setup))
loader.set_component( mock_integration(
self.hass, self.hass,
'test_component3',
MockModule('test_component3', setup=component_track_setup)) MockModule('test_component3', setup=component_track_setup))
@callback @callback
@ -575,8 +571,7 @@ def test_component_cannot_depend_config(hass):
@asyncio.coroutine @asyncio.coroutine
def test_component_warn_slow_setup(hass): def test_component_warn_slow_setup(hass):
"""Warn we log when a component setup takes a long time.""" """Warn we log when a component setup takes a long time."""
loader.set_component( mock_integration(hass, MockModule('test_component1'))
hass, 'test_component1', MockModule('test_component1'))
with mock.patch.object(hass.loop, 'call_later', mock.MagicMock()) \ with mock.patch.object(hass.loop, 'call_later', mock.MagicMock()) \
as mock_call: as mock_call:
result = yield from setup.async_setup_component( result = yield from setup.async_setup_component(
@ -596,8 +591,8 @@ def test_component_warn_slow_setup(hass):
@asyncio.coroutine @asyncio.coroutine
def test_platform_no_warn_slow(hass): def test_platform_no_warn_slow(hass):
"""Do not warn for long entity setup time.""" """Do not warn for long entity setup time."""
loader.set_component( mock_integration(
hass, 'test_component1', hass,
MockModule('test_component1', platform_schema=PLATFORM_SCHEMA)) MockModule('test_component1', platform_schema=PLATFORM_SCHEMA))
with mock.patch.object(hass.loop, 'call_later', mock.MagicMock()) \ with mock.patch.object(hass.loop, 'call_later', mock.MagicMock()) \
as mock_call: as mock_call:

View File

@ -0,0 +1 @@
"""Configuration that's used when running tests."""

View File

@ -0,0 +1 @@
"""A collection of custom integrations used when running tests."""

View File

@ -0,0 +1 @@
"""An integration with several platforms used with unit tests."""

View File

@ -0,0 +1,8 @@
{
"domain": "test",
"name": "Test Components",
"documentation": "http://example.com",
"requirements": [],
"dependencies": [],
"codeowners": []
}