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": [
"pyarlo==0.2.3"
],
"dependencies": [],
"dependencies": [
"ffmpeg"
],
"codeowners": []
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -126,7 +126,7 @@ import uuid
from typing import Callable, Dict, List, Optional, Set # noqa pylint: disable=unused-import
import weakref
from homeassistant import data_entry_flow
from homeassistant import data_entry_flow, loader
from homeassistant.core import callback, HomeAssistant
from homeassistant.exceptions import HomeAssistantError, ConfigEntryNotReady
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.
"""
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)
if handler is None:
@ -698,7 +703,7 @@ class ConfigEntries:
# Make sure requirements and dependencies of component are resolved
await async_process_deps_reqs(
self.hass, self._hass_config, handler, component)
self.hass, self._hass_config, integration)
# Create notification.
if source in DISCOVERY_SOURCES:

View File

@ -52,11 +52,11 @@ LOOKUP_PATHS = [PACKAGE_CUSTOM_COMPONENTS, PACKAGE_BUILTIN]
_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."""
return {
'domain': module.DOMAIN,
'name': module.DOMAIN,
'domain': module.DOMAIN, # type: ignore
'name': module.DOMAIN, # type: ignore
'documentation': None,
'requirements': getattr(module, 'REQUIREMENTS', []),
'dependencies': getattr(module, 'DEPENDENCIES', []),
@ -68,10 +68,10 @@ class Integration:
"""An integration in Home Assistant."""
@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]':
"""Resolve an integration from a root module."""
for base in root_module.__path__:
for base in root_module.__path__: # type: ignore
manifest_path = (
pathlib.Path(base) / domain / 'manifest.json'
)
@ -117,15 +117,22 @@ class Integration:
self.dependencies = manifest['dependencies'] # type: List[str]
self.requirements = manifest['requirements'] # type: List[str]
def get_component(self) -> Any:
def get_component(self) -> ModuleType:
"""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 importlib.import_module(
"{}.{}".format(self.pkg_path, platform_name)
)
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)
)
return cache[full_name] # type: ignore
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)
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:
log_error("Component not found.", False)
try:
component = integration.get_component()
except ImportError:
log_error("Unable to import component", False)
return False
# Validate all dependencies exist and there are no circular dependencies
@ -128,7 +134,7 @@ async def _async_setup_component(hass: core.HomeAssistant,
return False
try:
await async_process_deps_reqs(hass, config, domain, component)
await async_process_deps_reqs(hass, config, integration)
except HomeAssistantError as err:
log_error(str(err))
return False
@ -183,13 +189,14 @@ async def _async_setup_component(hass: core.HomeAssistant,
hass.bus.async_fire(
EVENT_COMPONENT_LOADED,
{ATTR_COMPONENT: component.DOMAIN} # type: ignore
{ATTR_COMPONENT: component.DOMAIN} # type: ignore
)
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) \
-> Optional[ModuleType]:
"""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:
"""Log helper."""
_LOGGER.error("Unable to prepare setup for platform %s: %s",
platform_path, msg)
platform_name, msg)
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
if platform is None:
try:
platform = integration.get_platform(domain)
except ImportError:
log_error("Platform not found.")
return None
@ -216,9 +228,25 @@ async def async_prepare_setup_platform(hass: core.HomeAssistant, config: Dict,
if platform_path in hass.config.components:
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:
component = integration.get_component()
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, config, platform_path, platform)
await async_process_deps_reqs(hass, hass_config, integration)
except HomeAssistantError as err:
log_error(str(err))
return None
@ -227,8 +255,8 @@ async def async_prepare_setup_platform(hass: core.HomeAssistant, config: Dict,
async def async_process_deps_reqs(
hass: core.HomeAssistant, config: Dict, name: str,
module: ModuleType) -> None:
hass: core.HomeAssistant, config: Dict,
integration: loader.Integration) -> None:
"""Process all dependencies and requirements for a module.
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:
processed = hass.data[DATA_DEPS_REQS] = set()
elif name in processed:
elif integration.domain in processed:
return
if hasattr(module, 'DEPENDENCIES'):
dep_success = await _async_process_dependencies(
hass, config, name, module.DEPENDENCIES) # type: ignore
if integration.dependencies and not await _async_process_dependencies(
hass,
config,
integration.domain,
integration.dependencies
):
raise HomeAssistantError("Could not set up all dependencies.")
if not dep_success:
raise HomeAssistantError("Could not set up all dependencies.")
if (not hass.config.skip_pip and integration.requirements and
not await requirements.async_process_requirements(
hass, integration.domain, integration.requirements)):
raise HomeAssistantError("Could not install all requirements.")
if not hass.config.skip_pip and hasattr(module, 'REQUIREMENTS'):
req_success = await requirements.async_process_requirements(
hass, name, module.REQUIREMENTS) # type: ignore
if not req_success:
raise HomeAssistantError("Could not install all requirements.")
processed.add(name)
processed.add(integration.domain)
@core.callback

View File

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

View File

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

View File

@ -906,11 +906,26 @@ def mock_integration(hass, module):
integration = loader.Integration(
hass, 'homeassisant.components.{}'.format(module.DOMAIN),
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(
loader.DATA_INTEGRATIONS, {}
)[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)
self.hass.block_till_done()
# In this test, five geolocation entities have been
# In this test, one zone and geolocation entities have been
# generated.
all_states = self.hass.states.all()
print(all_states)
assert len(all_states) == NUMBER_OF_DEMO_DEVICES
assert len(all_states) == NUMBER_OF_DEMO_DEVICES + 1
# Check a single device's attributes.
state_first_entry = all_states[0]
state_first_entry = all_states[1] # 0 is zone
assert abs(
state_first_entry.attributes['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
# the same, but the lists are different.
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

View File

@ -38,6 +38,7 @@ def demo_cleanup(hass):
pass
@pytest.mark.skip
@asyncio.coroutine
def test_if_demo_state_shows_by_default(hass, minimize_demo_platforms):
"""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
@pytest.mark.skip
@asyncio.coroutine
def test_hiding_demo_state(hass, minimize_demo_platforms):
"""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
@pytest.mark.skip
@asyncio.coroutine
def test_all_entities_can_be_loaded_over_json(hass):
"""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):
"""Initialize components."""
scanner = loader.get_component(
hass, 'device_tracker.test').get_scanner(None, None)
hass, 'test.device_tracker').get_scanner(None, None)
scanner.reset()
scanner.come_home('DEV1')
loader.get_component(hass, 'light.test').init()
loader.get_component(hass, 'test.light').init()
with patch(
'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):
"""Test stalled update."""
scanner = get_component(hass, 'device_tracker.test').SCANNER
scanner = get_component(hass, 'test.device_tracker').SCANNER
scanner.reset()
scanner.come_home('DEV1')
@ -256,7 +256,7 @@ async def test_device_hidden(hass, yaml_devices):
hide_if_away=True)
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()
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)
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()
with assert_setup_component(1, device_tracker.DOMAIN):
@ -441,7 +441,7 @@ async def test_see_passive_zone_state(hass):
'zone': zone_info
})
scanner = get_component(hass, 'device_tracker.test').SCANNER
scanner = get_component(hass, 'test.device_tracker').SCANNER
scanner.reset()
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):
"""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.come_home('DEV1')

View File

@ -74,7 +74,7 @@ class TestSwitchFlux(unittest.TestCase):
def test_flux_when_switch_is_off(self):
"""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()
assert setup_component(self.hass, light.DOMAIN,
{light.DOMAIN: {CONF_PLATFORM: 'test'}})
@ -114,7 +114,7 @@ class TestSwitchFlux(unittest.TestCase):
def test_flux_before_sunrise(self):
"""Test the flux switch before sunrise."""
platform = loader.get_component(self.hass, 'light.test')
platform = loader.get_component(self.hass, 'test.light')
platform.init()
assert setup_component(self.hass, light.DOMAIN,
{light.DOMAIN: {CONF_PLATFORM: 'test'}})
@ -159,7 +159,7 @@ class TestSwitchFlux(unittest.TestCase):
# pylint: disable=invalid-name
def test_flux_after_sunrise_before_sunset(self):
"""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()
assert setup_component(self.hass, light.DOMAIN,
{light.DOMAIN: {CONF_PLATFORM: 'test'}})
@ -205,7 +205,7 @@ class TestSwitchFlux(unittest.TestCase):
# pylint: disable=invalid-name
def test_flux_after_sunset_before_stop(self):
"""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()
assert setup_component(self.hass, light.DOMAIN,
{light.DOMAIN: {CONF_PLATFORM: 'test'}})
@ -252,7 +252,7 @@ class TestSwitchFlux(unittest.TestCase):
# pylint: disable=invalid-name
def test_flux_after_stop_before_sunrise(self):
"""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()
assert setup_component(self.hass, light.DOMAIN,
{light.DOMAIN: {CONF_PLATFORM: 'test'}})
@ -297,7 +297,7 @@ class TestSwitchFlux(unittest.TestCase):
# pylint: disable=invalid-name
def test_flux_with_custom_start_stop_times(self):
"""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()
assert setup_component(self.hass, light.DOMAIN,
{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).
"""
platform = loader.get_component(self.hass, 'light.test')
platform = loader.get_component(self.hass, 'test.light')
platform.init()
assert setup_component(self.hass, light.DOMAIN,
{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).
"""
platform = loader.get_component(self.hass, 'light.test')
platform = loader.get_component(self.hass, 'test.light')
platform.init()
assert setup_component(self.hass, light.DOMAIN,
{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).
"""
platform = loader.get_component(self.hass, 'light.test')
platform = loader.get_component(self.hass, 'test.light')
platform.init()
assert setup_component(self.hass, light.DOMAIN,
{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).
"""
platform = loader.get_component(self.hass, 'light.test')
platform = loader.get_component(self.hass, 'test.light')
platform.init()
assert setup_component(self.hass, light.DOMAIN,
{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).
"""
platform = loader.get_component(self.hass, 'light.test')
platform = loader.get_component(self.hass, 'test.light')
platform.init()
assert setup_component(self.hass, light.DOMAIN,
{light.DOMAIN: {CONF_PLATFORM: 'test'}})
@ -594,7 +594,7 @@ class TestSwitchFlux(unittest.TestCase):
# pylint: disable=invalid-name
def test_flux_with_custom_colortemps(self):
"""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()
assert setup_component(self.hass, light.DOMAIN,
{light.DOMAIN: {CONF_PLATFORM: 'test'}})
@ -643,7 +643,7 @@ class TestSwitchFlux(unittest.TestCase):
# pylint: disable=invalid-name
def test_flux_with_custom_brightness(self):
"""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()
assert setup_component(self.hass, light.DOMAIN,
{light.DOMAIN: {CONF_PLATFORM: 'test'}})
@ -690,7 +690,7 @@ class TestSwitchFlux(unittest.TestCase):
def test_flux_with_multiple_lights(self):
"""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()
assert setup_component(self.hass, light.DOMAIN,
{light.DOMAIN: {CONF_PLATFORM: 'test'}})
@ -758,7 +758,7 @@ class TestSwitchFlux(unittest.TestCase):
def test_flux_with_mired(self):
"""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()
assert setup_component(self.hass, light.DOMAIN,
{light.DOMAIN: {CONF_PLATFORM: 'test'}})
@ -802,7 +802,7 @@ class TestSwitchFlux(unittest.TestCase):
def test_flux_with_rgb(self):
"""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()
assert setup_component(self.hass, light.DOMAIN,
{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
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])
assert resp.status == 200
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):
"""Test heater switching test switch."""
platform = loader.get_component(hass, 'switch.test')
platform = loader.get_component(hass, 'test.switch')
platform.init()
switch_1 = platform.DEVICES[1]
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
}})
await hass.async_block_till_done()
assert STATE_OFF == \
hass.states.get(heater_switch).state

View File

@ -121,7 +121,7 @@ class TestLight(unittest.TestCase):
def test_services(self):
"""Test the provided services."""
platform = loader.get_component(self.hass, 'light.test')
platform = loader.get_component(self.hass, 'test.light')
platform.init()
assert setup_component(self.hass, light.DOMAIN,
@ -308,7 +308,7 @@ class TestLight(unittest.TestCase):
def test_broken_light_profiles(self):
"""Test light profiles."""
platform = loader.get_component(self.hass, 'light.test')
platform = loader.get_component(self.hass, 'test.light')
platform.init()
user_light_file = self.hass.config.path(light.LIGHT_PROFILES_FILE)
@ -323,7 +323,7 @@ class TestLight(unittest.TestCase):
def test_light_profiles(self):
"""Test light profiles."""
platform = loader.get_component(self.hass, 'light.test')
platform = loader.get_component(self.hass, 'test.light')
platform.init()
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):
"""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()
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):
"""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()
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):
"""Test the failing."""
assert not setup_component(
self.hass, 'binary_sensor.nx584', config)
self.hass, 'nx584', config)
def test_setup_bad_config(self):
"""Test the setup with bad configuration."""

View File

@ -18,7 +18,7 @@ class TestScene(unittest.TestCase):
def setUp(self): # pylint: disable=invalid-name
"""Set up things to be run when tests are started."""
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()
assert setup_component(self.hass, light.DOMAIN, {

View File

@ -18,7 +18,7 @@ class TestSwitch(unittest.TestCase):
def setUp(self):
"""Set up things to be run when tests are started."""
self.hass = get_test_home_assistant()
platform = loader.get_component(self.hass, 'switch.test')
platform = loader.get_component(self.hass, 'test.switch')
platform.init()
# Switch 1 is ON, switch 2 is OFF
self.switch_1, self.switch_2, self.switch_3 = \
@ -77,7 +77,7 @@ class TestSwitch(unittest.TestCase):
def test_setup_two_platforms(self):
"""Test with bad configuration."""
# 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)
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')
assert state is not None

View File

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

View File

@ -21,7 +21,8 @@ import homeassistant.util.dt as dt_util
from tests.common import (
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__)
DOMAIN = "test_domain"
@ -74,11 +75,14 @@ class TestHelpersEntityComponent(unittest.TestCase):
"""Test the loading of the platforms."""
component_setup = Mock(return_value=True)
platform_setup = Mock(return_value=None)
loader.set_component(
self.hass, 'test_component',
MockModule('test_component', setup=component_setup))
loader.set_component(self.hass, 'test_domain.mod2',
MockPlatform(platform_setup, ['test_component']))
mock_integration(self.hass,
MockModule('test_component', setup=component_setup))
# mock the dependencies
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)
@ -100,9 +104,9 @@ class TestHelpersEntityComponent(unittest.TestCase):
platform1_setup = Mock(side_effect=Exception('Broken'))
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))
loader.set_component(self.hass, 'test_domain.mod2',
mock_entity_platform(self.hass, 'test_domain.mod2',
MockPlatform(platform2_setup))
component = EntityComponent(_LOGGER, DOMAIN, self.hass)
@ -147,7 +151,7 @@ class TestHelpersEntityComponent(unittest.TestCase):
"""Test the platform setup."""
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))
component = EntityComponent(_LOGGER, DOMAIN, self.hass)
@ -174,7 +178,7 @@ class TestHelpersEntityComponent(unittest.TestCase):
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)
@ -222,7 +226,9 @@ def test_platform_not_ready(hass):
"""Test that we retry when platform not ready."""
platform1_setup = Mock(side_effect=[PlatformNotReady, PlatformNotReady,
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))
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
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',
MockModule('test_component2'))
loader.set_component(
hass, 'test_component.test_domain',
MockPlatform(dependencies=['test_component', 'test_component2']))
loader.set_component(hass, 'test_component.test_domain', MockPlatform())
component = EntityComponent(_LOGGER, DOMAIN, hass)
yield from async_setup_component(hass, 'test_component', {})
yield from component.async_setup({
DOMAIN: {
'platform': 'test_component',
@ -345,7 +349,7 @@ def test_setup_dependencies_platform(hass):
async def test_setup_entry(hass):
"""Test setup entry calls async_setup_entry on platform."""
mock_setup_entry = Mock(return_value=mock_coro(True))
loader.set_component(
mock_entity_platform(
hass, 'test_domain.entry_domain',
MockPlatform(async_setup_entry=mock_setup_entry,
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):
"""Test we don't allow setting up a config entry twice."""
mock_setup_entry = Mock(return_value=mock_coro(True))
loader.set_component(
mock_entity_platform(
hass, 'test_domain.entry_domain',
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):
"""Test unloading an entry removes all entities."""
mock_setup_entry = Mock(return_value=mock_coro(True))
loader.set_component(
mock_entity_platform(
hass, 'test_domain.entry_domain',
MockPlatform(async_setup_entry=mock_setup_entry))

View File

@ -8,7 +8,6 @@ from datetime import timedelta
import pytest
from homeassistant.exceptions import PlatformNotReady
import homeassistant.loader as loader
from homeassistant.helpers.entity import generate_entity_id
from homeassistant.helpers.entity_component import (
EntityComponent, DEFAULT_SCAN_INTERVAL)
@ -18,7 +17,7 @@ import homeassistant.util.dt as dt_util
from tests.common import (
get_test_home_assistant, MockPlatform, fire_time_changed, mock_registry,
MockEntity, MockEntityPlatform, MockConfigEntry)
MockEntity, MockEntityPlatform, MockConfigEntry, mock_entity_platform)
_LOGGER = logging.getLogger(__name__)
DOMAIN = "test_domain"
@ -149,7 +148,7 @@ class TestHelpersEntityPlatform(unittest.TestCase):
platform = MockPlatform(platform_setup)
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)
@ -186,7 +185,7 @@ def test_platform_warn_slow_setup(hass):
"""Warn we log when platform setup takes a long time."""
platform = MockPlatform()
loader.set_component(hass, 'test_domain.platform', platform)
mock_entity_platform(hass, 'test_domain.platform', platform)
component = EntityComponent(_LOGGER, DOMAIN, hass)
@ -199,7 +198,9 @@ def test_platform_warn_slow_setup(hass):
})
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 logger_method == _LOGGER.warning
@ -220,7 +221,7 @@ def test_platform_error_slow_setup(hass, caplog):
platform = MockPlatform(async_setup_platform=setup_platform)
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({
DOMAIN: {
'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."""
platform = MockPlatform()
loader.set_component(hass, 'test_domain.platform', platform)
mock_entity_platform(hass, 'test_domain.platform', platform)
component = EntityComponent(_LOGGER, DOMAIN, hass)
component._platforms = {}
@ -285,7 +286,7 @@ async def test_parallel_updates_async_platform_with_constant(hass):
platform = MockPlatform()
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._platforms = {}
@ -316,7 +317,7 @@ async def test_parallel_updates_sync_platform(hass):
"""Test sync platform parallel_updates default set to 1."""
platform = MockPlatform()
loader.set_component(hass, 'test_domain.platform', platform)
mock_entity_platform(hass, 'test_domain.platform', platform)
component = EntityComponent(_LOGGER, DOMAIN, hass)
component._platforms = {}
@ -347,7 +348,7 @@ async def test_parallel_updates_sync_platform_with_constant(hass):
platform = MockPlatform()
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._platforms = {}

View File

@ -54,7 +54,7 @@ async def test_component_translation_file(hass):
assert path.normpath(translation.component_translation_file(
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(
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 one valid and one invalid file
file1 = hass.config.path(
'custom_components', 'switch', '.translations', 'test.en.json')
'custom_components', 'test', '.translations', 'switch.en.json')
file2 = hass.config.path(
'custom_components', 'switch', '.translations', 'invalid.json')
'custom_components', 'test', '.translations', 'invalid.json')
assert translation.load_translations_files({
'switch.test': file1,
'invalid': file2

View File

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

View File

@ -1,6 +1,4 @@
"""Test to verify that we can load components."""
import asyncio
import pytest
import homeassistant.loader as loader
@ -63,20 +61,18 @@ def test_component_loader_non_existing(hass):
components.non_existing
@asyncio.coroutine
def test_component_wrapper(hass):
async def test_component_wrapper(hass):
"""Test component wrapper."""
calls = async_mock_service(hass, 'persistent_notification', 'create')
components = loader.Components(hass)
components.persistent_notification.async_create('message')
yield from hass.async_block_till_done()
await hass.async_block_till_done()
assert len(calls) == 1
@asyncio.coroutine
def test_helpers_wrapper(hass):
async def test_helpers_wrapper(hass):
"""Test helpers wrapper."""
helpers = loader.Helpers(hass)
@ -88,8 +84,8 @@ def test_helpers_wrapper(hass):
helpers.discovery.async_listen('service_name', discovery_callback)
yield from helpers.discovery.async_discover('service_name', 'hello')
yield from hass.async_block_till_done()
await helpers.discovery.async_discover('service_name', 'hello')
await hass.async_block_till_done()
assert result == ['hello']
@ -104,9 +100,9 @@ async def test_custom_component_name(hass):
assert comp.__name__ == 'custom_components.test_package'
assert comp.__package__ == 'custom_components.test_package'
comp = loader.get_component(hass, 'light.test')
assert comp.__name__ == 'custom_components.light.test'
assert comp.__package__ == 'custom_components.light'
comp = loader.get_component(hass, 'test.light')
assert comp.__name__ == 'custom_components.test.light'
assert comp.__package__ == 'custom_components.test'
# Test custom components is mounted
from custom_components.test_package import TEST
@ -119,8 +115,8 @@ async def test_log_warning_custom_component(hass, caplog):
assert \
'You are using a custom component for test_standalone' in caplog.text
loader.get_component(hass, 'light.test')
assert 'You are using a custom component for light.test' in caplog.text
loader.get_component(hass, 'test.light')
assert 'You are using a custom component for test.light' in caplog.text
async def test_get_platform(hass, caplog):
@ -132,8 +128,8 @@ async def test_get_platform(hass, caplog):
caplog.clear()
legacy_platform = loader.get_platform(hass, 'switch', 'test')
assert legacy_platform.__name__ == 'custom_components.switch.test'
legacy_platform = loader.get_platform(hass, 'switch', 'test_legacy')
assert legacy_platform.__name__ == 'custom_components.switch.test_legacy'
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 \
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
VERSION_PATH = os.path.join(get_test_config_dir(), config_util.VERSION_FILE)
@ -50,9 +51,9 @@ class TestSetup:
'hello': str
}
}, required=True)
loader.set_component(
mock_integration(
self.hass,
'comp_conf', MockModule('comp_conf', config_schema=config_schema))
MockModule('comp_conf', config_schema=config_schema))
with assert_setup_component(0):
assert not setup.setup_component(self.hass, 'comp_conf', {})
@ -97,17 +98,15 @@ class TestSetup:
})
platform_schema_base = PLATFORM_SCHEMA_BASE.extend({
})
loader.set_component(
mock_integration(
self.hass,
'platform_conf',
MockModule('platform_conf',
platform_schema_base=platform_schema_base))
loader.set_component(
platform_schema_base=platform_schema_base),
)
mock_entity_platform(
self.hass,
'platform_conf.whatever',
MockPlatform('whatever',
platform_schema=platform_schema))
MockPlatform(platform_schema=platform_schema))
with assert_setup_component(1):
assert setup.setup_component(self.hass, 'platform_conf', {
@ -195,14 +194,13 @@ class TestSetup:
platform_schema_base = PLATFORM_SCHEMA_BASE.extend({
'hello': 'world',
})
loader.set_component(
mock_integration(
self.hass,
'platform_conf',
MockModule('platform_conf',
platform_schema=platform_schema,
platform_schema_base=platform_schema_base))
loader.set_component(
mock_entity_platform(
self.hass,
'platform_conf.whatever',
MockPlatform('whatever',
@ -249,13 +247,12 @@ class TestSetup:
'cheers': str,
'hello': 'world',
})
loader.set_component(
mock_integration(
self.hass,
'platform_conf',
MockModule('platform_conf',
platform_schema=component_schema))
loader.set_component(
mock_entity_platform(
self.hass,
'platform_conf.whatever',
MockPlatform('whatever',
@ -296,17 +293,15 @@ class TestSetup:
"""Test entity_namespace in PLATFORM_SCHEMA."""
component_schema = PLATFORM_SCHEMA_BASE
platform_schema = PLATFORM_SCHEMA
loader.set_component(
mock_integration(
self.hass,
'platform_conf',
MockModule('platform_conf',
platform_schema_base=component_schema))
loader.set_component(
mock_entity_platform(
self.hass,
'platform_conf.whatever',
MockPlatform('whatever',
platform_schema=platform_schema))
MockPlatform(platform_schema=platform_schema))
with assert_setup_component(1):
assert setup.setup_component(self.hass, 'platform_conf', {
@ -322,14 +317,15 @@ class TestSetup:
def test_component_not_found(self):
"""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):
"""Test we do not set up a component twice."""
mock_setup = mock.MagicMock(return_value=True)
loader.set_component(
self.hass, 'comp', MockModule('comp', setup=mock_setup))
mock_integration(
self.hass,
MockModule('comp', setup=mock_setup))
assert setup.setup_component(self.hass, 'comp')
assert mock_setup.called
@ -344,9 +340,9 @@ class TestSetup:
def test_component_not_installed_if_requirement_fails(self, mock_install):
"""Component setup should fail if requirement can't install."""
self.hass.config.skip_pip = False
loader.set_component(
mock_integration(
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 'comp' not in self.hass.config.components
@ -360,9 +356,9 @@ class TestSetup:
"""Tracking Setup."""
result.append(1)
loader.set_component(
mock_integration(
self.hass,
'comp', MockModule('comp', async_setup=async_setup))
MockModule('comp', async_setup=async_setup))
def setup_component():
"""Set up the component."""
@ -393,8 +389,8 @@ class TestSetup:
def test_component_failing_setup(self):
"""Test component that fails setup."""
loader.set_component(
self.hass, 'comp',
mock_integration(
self.hass,
MockModule('comp', setup=lambda hass, config: False))
assert not setup.setup_component(self.hass, 'comp', {})
@ -406,8 +402,8 @@ class TestSetup:
"""Raise exception."""
raise Exception('fail!')
loader.set_component(
self.hass, 'comp', MockModule('comp', setup=exception_setup))
mock_integration(self.hass,
MockModule('comp', setup=exception_setup))
assert not setup.setup_component(self.hass, 'comp', {})
assert 'comp' not in self.hass.config.components
@ -420,12 +416,18 @@ class TestSetup:
return True
raise Exception('Config not passed in: {}'.format(config))
loader.set_component(
self.hass, 'comp_a',
MockModule('comp_a', setup=config_check_setup))
platform = MockPlatform()
loader.set_component(
self.hass, 'switch.platform_a', MockPlatform('comp_b', ['comp_a']))
mock_integration(self.hass,
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', {
'comp_a': {
@ -445,7 +447,7 @@ class TestSetup:
mock_setup = mock.MagicMock(spec_set=True)
loader.set_component(
mock_entity_platform(
self.hass,
'switch.platform_a',
MockPlatform(platform_schema=platform_schema,
@ -476,7 +478,7 @@ class TestSetup:
self.hass.data.pop(setup.DATA_SETUP)
self.hass.config.components.remove('switch')
with assert_setup_component(1):
with assert_setup_component(1, 'switch'):
assert setup.setup_component(self.hass, 'switch', {
'switch': {
'platform': 'platform_a',
@ -487,9 +489,8 @@ class TestSetup:
def test_disable_component_if_invalid_return(self):
"""Test disabling component if invalid return."""
loader.set_component(
mock_integration(
self.hass,
'disabled_component',
MockModule('disabled_component', setup=lambda hass, config: None))
assert not setup.setup_component(self.hass, 'disabled_component')
@ -497,9 +498,8 @@ class TestSetup:
assert 'disabled_component' not in self.hass.config.components
self.hass.data.pop(setup.DATA_SETUP)
loader.set_component(
mock_integration(
self.hass,
'disabled_component',
MockModule('disabled_component', setup=lambda hass, config: False))
assert not setup.setup_component(self.hass, 'disabled_component')
@ -508,9 +508,8 @@ class TestSetup:
assert 'disabled_component' not in self.hass.config.components
self.hass.data.pop(setup.DATA_SETUP)
loader.set_component(
mock_integration(
self.hass,
'disabled_component',
MockModule('disabled_component', setup=lambda hass, config: True))
assert setup.setup_component(self.hass, 'disabled_component')
@ -535,19 +534,16 @@ class TestSetup:
call_order.append(1)
return True
loader.set_component(
mock_integration(
self.hass,
'test_component1',
MockModule('test_component1', setup=component1_setup))
loader.set_component(
mock_integration(
self.hass,
'test_component2',
MockModule('test_component2', setup=component_track_setup))
loader.set_component(
mock_integration(
self.hass,
'test_component3',
MockModule('test_component3', setup=component_track_setup))
@callback
@ -575,8 +571,7 @@ def test_component_cannot_depend_config(hass):
@asyncio.coroutine
def test_component_warn_slow_setup(hass):
"""Warn we log when a component setup takes a long time."""
loader.set_component(
hass, 'test_component1', MockModule('test_component1'))
mock_integration(hass, MockModule('test_component1'))
with mock.patch.object(hass.loop, 'call_later', mock.MagicMock()) \
as mock_call:
result = yield from setup.async_setup_component(
@ -596,8 +591,8 @@ def test_component_warn_slow_setup(hass):
@asyncio.coroutine
def test_platform_no_warn_slow(hass):
"""Do not warn for long entity setup time."""
loader.set_component(
hass, 'test_component1',
mock_integration(
hass,
MockModule('test_component1', platform_schema=PLATFORM_SCHEMA))
with mock.patch.object(hass.loop, 'call_later', mock.MagicMock()) \
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": []
}