def test_integration_properties(hass): """Test integration properties.""" integration = loader.Integration( hass, "homeassistant.components.hue", None, { "name": "Philips Hue", "domain": "hue", "dependencies": ["test-dep"], "requirements": ["test-req==1.0.0"], }, ) assert integration.name == "Philips Hue" assert integration.domain == "hue" assert integration.dependencies == ["test-dep"] assert integration.requirements == ["test-req==1.0.0"] assert integration.is_built_in is True integration = loader.Integration( hass, "custom_components.hue", None, { "name": "Philips Hue", "domain": "hue", "dependencies": ["test-dep"], "requirements": ["test-req==1.0.0"], }, ) assert integration.is_built_in is False
async def test_custom_integration_missing_version(hass, caplog): """Test that we log a warning when custom integrations are missing a version.""" test_integration_1 = loader.Integration( hass, "custom_components.test1", None, {"domain": "test1"} ) test_integration_2 = loader.Integration( hass, "custom_components.test2", None, loader.manifest_from_legacy_module("test2", "custom_components.test2"), ) with patch("homeassistant.loader.async_get_custom_components") as mock_get: mock_get.return_value = { "test1": test_integration_1, "test2": test_integration_2, } await loader.async_get_integration(hass, "test1") assert ( "No 'version' key in the manifest file for custom integration 'test1'." in caplog.text ) await loader.async_get_integration(hass, "test2") assert ( "No 'version' key in the manifest file for custom integration 'test2'." in caplog.text )
async def test_custom_integration_version_not_valid(hass, caplog): """Test that we log a warning when custom integrations have a invalid version.""" test_integration1 = loader.Integration( hass, "custom_components.test", None, {"domain": "test1", "version": "test"} ) test_integration2 = loader.Integration( hass, "custom_components.test", None, {"domain": "test2"} ) with patch("homeassistant.loader.async_get_custom_components") as mock_get: mock_get.return_value = {"test1": test_integration1, "test2": test_integration2} with pytest.raises(loader.IntegrationNotFound): await loader.async_get_integration(hass, "test1") assert ( "The custom integration 'test1' does not have a valid version key (test) in the manifest file and was blocked from loading." in caplog.text ) with pytest.raises(loader.IntegrationNotFound): await loader.async_get_integration(hass, "test2") assert ( "The custom integration 'test2' does not have a valid version key (None) in the manifest file and was blocked from loading." in caplog.text )
def _get_test_integration_with_usb_matcher(hass, name, config_flow): """Return a generated test integration with a usb matcher.""" return loader.Integration( hass, f"homeassistant.components.{name}", None, { "name": name, "domain": name, "config_flow": config_flow, "dependencies": [], "requirements": [], "usb": [ { "vid": "10C4", "pid": "EA60", "known_devices": ["slae.sh cc2652rb stick"], }, {"vid": "1CF1", "pid": "0030", "known_devices": ["Conbee II"]}, { "vid": "1A86", "pid": "7523", "known_devices": ["Electrolama zig-a-zig-ah"], }, {"vid": "10C4", "pid": "8A2A", "known_devices": ["Nortek HUSBZB-1"]}, ], }, )
def _get_test_integration_with_zeroconf_matcher(hass, name, config_flow): """Return a generated test integration with a zeroconf matcher.""" return loader.Integration( hass, f"homeassistant.components.{name}", None, { "name": name, "domain": name, "config_flow": config_flow, "dependencies": [], "requirements": [], "zeroconf": [{ "type": f"_{name}._tcp.local.", "name": f"{name}*" }], "homekit": { "models": [name] }, "ssdp": [{ "manufacturer": name, "modelName": name }], }, )
async def test_service_description(hass): """Test service description defined in doc_string.""" await setup_script( hass, None, dt(2020, 7, 1, 11, 59, 59, 999999), """ @service def func_no_doc_string(param1=None): pass @service def func_simple_doc_string(param2=None, param3=None): \"\"\"This is func2_simple_doc_string.\"\"\" pass @service def func_yaml_doc_string(param2=None, param3=None): \"\"\"yaml description: This is func_yaml_doc_string. fields: param1: description: first argument example: 12 param2: description: second argument example: 34 \"\"\" pass """, ) integration = loader.Integration( hass, "custom_components.pyscript", pathlib.Path("custom_components/pyscript"), {"name": "pyscript", "dependencies": [], "requirements": [], "domain": "automation"}, ) with patch( "homeassistant.loader.async_get_custom_components", return_value={"pyscript": integration}, ): descriptions = (await async_get_all_descriptions(hass))[DOMAIN] assert descriptions["func_no_doc_string"]["description"] == "pyscript function func_no_doc_string()" assert descriptions["func_no_doc_string"]["fields"] == {"param1": {"description": "argument param1"}} assert descriptions["func_simple_doc_string"]["description"] == "This is func2_simple_doc_string." assert descriptions["func_simple_doc_string"]["fields"] == { "param2": {"description": "argument param2"}, "param3": {"description": "argument param3"}, } assert descriptions["func_yaml_doc_string"]["description"] == "This is func_yaml_doc_string." assert descriptions["func_yaml_doc_string"]["fields"] == { "param1": {"description": "first argument", "example": "12"}, "param2": {"description": "second argument", "example": "34"}, }
def mock_integration(hass, module): """Mock an integration.""" integration = loader.Integration( hass, f"homeassistant.components.{module.DOMAIN}", None, module.mock_manifest(), ) _LOGGER.info("Adding mock integration: %s", module.DOMAIN) hass.data.setdefault(loader.DATA_INTEGRATIONS, {})[module.DOMAIN] = integration hass.data.setdefault(loader.DATA_COMPONENTS, {})[module.DOMAIN] = module
def _get_test_integration(hass, name, config_flow): """Return a generated test integration.""" return loader.Integration( hass, "homeassistant.components.{}".format(name), None, { 'name': name, 'domain': name, 'config_flow': config_flow, 'dependencies': [], 'requirements': []})
async def setup_script(hass, notify_q, now, source): """Initialize and load the given pyscript.""" scripts = [ "/some/config/dir/pyscripts/hello.py", ] integration = loader.Integration( hass, "config.custom_components.pyscript", pathlib.Path("config/custom_components/pyscript"), { "name": "pyscript", "dependencies": [], "requirements": [], "domain": "automation", }, ) with patch( "homeassistant.loader.async_get_integration", return_value=integration, ), patch("config.custom_components.pyscript.os.path.isdir", return_value=True), patch( "config.custom_components.pyscript.glob.iglob", return_value=scripts), patch( "config.custom_components.pyscript.open", mock_open(read_data=source), create=True, ), patch("config.custom_components.pyscript.trigger.dt_now", return_value=now): assert await async_setup_component(hass, "pyscript", {}) # # I'm not sure how to run the mock all the time, so just force the dt_now() # trigger function to return the given list of times in now. # def return_next_time(): nonlocal now if isinstance(now, list): if len(now) > 1: return now.pop(0) return now[0] return now trigger.__dict__["dt_now"] = return_next_time if notify_q: async def state_changed(event): var_name = event.data["entity_id"] if var_name != "pyscript.done": return value = event.data["new_state"].state await notify_q.put(value) hass.bus.async_listen(EVENT_STATE_CHANGED, state_changed)
async def test_init_custom_integration(hass): """Test initializing flow for custom integration.""" integration = loader.Integration(hass, 'custom_components.hue', None, { 'name': 'Hue', 'dependencies': [], 'requirements': [], 'domain': 'hue', }) with pytest.raises(data_entry_flow.UnknownHandler): with patch('homeassistant.loader.async_get_integration', return_value=mock_coro(integration)): await hass.config_entries.flow.async_init('bla')
def test_integration_properties(hass): """Test integration properties.""" integration = loader.Integration( hass, 'homeassistant.components.hue', None, { 'name': 'Philips Hue', 'domain': 'hue', 'dependencies': ['test-dep'], 'requirements': ['test-req==1.0.0'], }) assert integration.name == "Philips Hue" assert integration.domain == 'hue' assert integration.dependencies == ['test-dep'] assert integration.requirements == ['test-req==1.0.0']
def _get_test_integration(hass, name, config_flow): """Return a generated test integration.""" return loader.Integration( hass, f"homeassistant.components.{name}", None, { "name": name, "domain": name, "config_flow": config_flow, "dependencies": [], "requirements": [], }, )
async def test_custom_integration_version_not_valid(hass, caplog): """Test that we log a warning when custom integrations have a invalid version.""" test_integration = loader.Integration( hass, "custom_components.test", None, {"domain": "test", "version": "test"} ) with patch("homeassistant.loader.async_get_custom_components") as mock_get: mock_get.return_value = {"test": test_integration} await loader.async_get_integration(hass, "test") assert ( "'test' is not a valid version for custom integration 'test'." in caplog.text )
async def test_custom_integration_missing_version(hass, caplog): """Test trying to load a custom integration without a version twice does not deadlock.""" test_integration_1 = loader.Integration( hass, "custom_components.test1", None, {"domain": "test1"} ) with patch("homeassistant.loader.async_get_custom_components") as mock_get: mock_get.return_value = { "test1": test_integration_1, } with pytest.raises(loader.IntegrationNotFound): await loader.async_get_integration(hass, "test1") with pytest.raises(loader.IntegrationNotFound): await loader.async_get_integration(hass, "test1")
async def test_loggers(hass): """Test we can fetch the loggers from the integration.""" name = "dummy" integration = loader.Integration( hass, f"homeassistant.components.{name}", None, { "name": name, "domain": name, "config_flow": True, "dependencies": [], "requirements": [], "loggers": ["name1", "name2"], }, ) assert integration.loggers == ["name1", "name2"]
def _get_test_integration_with_bluetooth_matcher(hass, name, config_flow): """Return a generated test integration with a bluetooth matcher.""" return loader.Integration( hass, f"homeassistant.components.{name}", None, { "name": name, "domain": name, "config_flow": config_flow, "bluetooth": [ { "local_name": "Prodigio_*", }, ], }, )
def _get_test_integration(hass, name, config_flow): """Return a generated test integration.""" return loader.Integration( hass, f"homeassistant.components.{name}", None, { "name": name, "domain": name, "config_flow": config_flow, "dependencies": [], "requirements": [], "zeroconf": [f"_{name}._tcp.local."], "homekit": {"models": [name]}, "ssdp": [{"manufacturer": name, "modelName": name}], "mqtt": [f"{name}/discovery"], }, )
async def test_init_custom_integration(hass): """Test initializing flow for custom integration.""" integration = loader.Integration( hass, "custom_components.hue", None, { "name": "Hue", "dependencies": [], "requirements": [], "domain": "hue" }, ) with pytest.raises(data_entry_flow.UnknownHandler): with patch( "homeassistant.loader.async_get_integration", return_value=mock_coro(integration), ): await hass.config_entries.flow.async_init("bla")
def mock_integration(hass, module): """Mock an integration.""" integration = loader.Integration( hass, f"homeassistant.components.{module.DOMAIN}", None, module.mock_manifest()) def mock_import_platform(platform_name): raise ImportError( f"Mocked unable to import platform '{platform_name}'", name=f"{integration.pkg_path}.{platform_name}", ) integration._import_platform = mock_import_platform _LOGGER.info("Adding mock integration: %s", module.DOMAIN) hass.data.setdefault(loader.DATA_INTEGRATIONS, {})[module.DOMAIN] = integration hass.data.setdefault(loader.DATA_COMPONENTS, {})[module.DOMAIN] = module return integration
def _get_test_integration_with_dhcp_matcher(hass, name, config_flow): """Return a generated test integration with a dhcp matcher.""" return loader.Integration( hass, f"homeassistant.components.{name}", None, { "name": name, "domain": name, "config_flow": config_flow, "dependencies": [], "requirements": [], "zeroconf": [], "dhcp": [ {"hostname": "tesla_*", "macaddress": "4CFCAA*"}, {"hostname": "tesla_*", "macaddress": "044EAF*"}, {"hostname": "tesla_*", "macaddress": "98ED5C*"}, ], "homekit": {"models": [name]}, "ssdp": [{"manufacturer": name, "modelName": name}], }, )
async def test_setup_fails_on_no_dir(hass, caplog): """Test we fail setup when no dir found.""" integration = loader.Integration( hass, "config.custom_components.pyscript", pathlib.Path("config/custom_components/pyscript"), { "name": "pyscript", "dependencies": [], "requirements": [], "domain": "automation", }, ) with patch( "homeassistant.loader.async_get_integration", return_value=integration, ), patch("config.custom_components.pyscript.os.path.isdir", return_value=False): res = await async_setup_component(hass, "pyscript", {}) assert not res assert "Folder pyscript not found in configuration folder" in caplog.text
def mock_integration(hass, module, built_in=True): """Mock an integration.""" integration = loader.Integration( hass, f"{loader.PACKAGE_BUILTIN}.{module.DOMAIN}" if built_in else f"{loader.PACKAGE_CUSTOM_COMPONENTS}.{module.DOMAIN}", None, module.mock_manifest(), ) def mock_import_platform(platform_name): raise ImportError( f"Mocked unable to import platform '{platform_name}'", name=f"{integration.pkg_path}.{platform_name}", ) integration._import_platform = mock_import_platform _LOGGER.info("Adding mock integration: %s", module.DOMAIN) hass.data.setdefault(loader.DATA_INTEGRATIONS, {})[module.DOMAIN] = integration hass.data.setdefault(loader.DATA_COMPONENTS, {})[module.DOMAIN] = module return integration
def test_integration_properties(hass): """Test integration properties.""" integration = loader.Integration( hass, "homeassistant.components.hue", None, { "name": "Philips Hue", "domain": "hue", "dependencies": ["test-dep"], "requirements": ["test-req==1.0.0"], "zeroconf": ["_hue._tcp.local."], "homekit": {"models": ["BSB002"]}, "dhcp": [ {"hostname": "tesla_*", "macaddress": "4CFCAA*"}, {"hostname": "tesla_*", "macaddress": "044EAF*"}, {"hostname": "tesla_*", "macaddress": "98ED5C*"}, ], "ssdp": [ { "manufacturer": "Royal Philips Electronics", "modelName": "Philips hue bridge 2012", }, { "manufacturer": "Royal Philips Electronics", "modelName": "Philips hue bridge 2015", }, {"manufacturer": "Signify", "modelName": "Philips hue bridge 2015"}, ], "mqtt": ["hue/discovery"], "version": "1.0.0", }, ) assert integration.name == "Philips Hue" assert integration.domain == "hue" assert integration.homekit == {"models": ["BSB002"]} assert integration.zeroconf == ["_hue._tcp.local."] assert integration.dhcp == [ {"hostname": "tesla_*", "macaddress": "4CFCAA*"}, {"hostname": "tesla_*", "macaddress": "044EAF*"}, {"hostname": "tesla_*", "macaddress": "98ED5C*"}, ] assert integration.ssdp == [ { "manufacturer": "Royal Philips Electronics", "modelName": "Philips hue bridge 2012", }, { "manufacturer": "Royal Philips Electronics", "modelName": "Philips hue bridge 2015", }, {"manufacturer": "Signify", "modelName": "Philips hue bridge 2015"}, ] assert integration.mqtt == ["hue/discovery"] assert integration.dependencies == ["test-dep"] assert integration.requirements == ["test-req==1.0.0"] assert integration.is_built_in is True assert integration.version == "1.0.0" integration = loader.Integration( hass, "custom_components.hue", None, { "name": "Philips Hue", "domain": "hue", "dependencies": ["test-dep"], "requirements": ["test-req==1.0.0"], }, ) assert integration.is_built_in is False assert integration.homekit is None assert integration.zeroconf is None assert integration.dhcp is None assert integration.ssdp is None assert integration.mqtt is None assert integration.version is None integration = loader.Integration( hass, "custom_components.hue", None, { "name": "Philips Hue", "domain": "hue", "dependencies": ["test-dep"], "zeroconf": [{"type": "_hue._tcp.local.", "name": "hue*"}], "requirements": ["test-req==1.0.0"], }, ) assert integration.is_built_in is False assert integration.homekit is None assert integration.zeroconf == [{"type": "_hue._tcp.local.", "name": "hue*"}] assert integration.dhcp is None assert integration.ssdp is None
async def test_reload(hass, caplog): """Test reload.""" notify_q = asyncio.Queue(0) now = dt(2020, 7, 1, 11, 59, 59, 999999) source0 = """ seq_num = 0 @time_trigger def func_startup_sync(): global seq_num seq_num += 1 log.info(f"func_startup_sync setting pyscript.done = {seq_num}") pyscript.done = seq_num @service @state_trigger("pyscript.f1var1 == '1'") def func1(var_name=None, value=None): global seq_num seq_num += 1 log.info(f"func1 var = {var_name}, value = {value}") pyscript.done = [seq_num, var_name, int(value)] """ source1 = """ seq_num = 10 @time_trigger def func_startup_sync(): global seq_num seq_num += 1 log.info(f"func_startup_sync setting pyscript.done = {seq_num}") pyscript.done = seq_num @service @state_trigger("pyscript.f5var1 == '1'") def func5(var_name=None, value=None): global seq_num seq_num += 1 log.info(f"func5 var = {var_name}, value = {value}") pyscript.done = [seq_num, var_name, int(value)] """ await setup_script(hass, notify_q, now, source0) # # run and reload 6 times with different sournce files to make sure seqNum # gets reset, autostart of func_startup_sync happens and triggers work each time # # first time: fire event to startup triggers and run func_startup_sync # hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED) for i in range(6): if i & 1: seq_num = 10 assert not hass.services.has_service("pyscript", "func1") assert hass.services.has_service("pyscript", "reload") assert hass.services.has_service("pyscript", "func5") seq_num += 1 assert literal_eval(await wait_until_done(notify_q)) == seq_num seq_num += 1 # initialize the trigger and active variables hass.states.async_set("pyscript.f5var1", 0) # try some values that shouldn't work, then one that does hass.states.async_set("pyscript.f5var1", "string") hass.states.async_set("pyscript.f5var1", 1) assert literal_eval(await wait_until_done(notify_q)) == [ seq_num, "pyscript.f5var1", 1, ] assert "func5 var = pyscript.f5var1, value = 1" in caplog.text next_source = source0 else: seq_num = 0 assert hass.services.has_service("pyscript", "func1") assert hass.services.has_service("pyscript", "reload") assert not hass.services.has_service("pyscript", "func5") seq_num += 1 assert literal_eval(await wait_until_done(notify_q)) == seq_num seq_num += 1 # initialize the trigger and active variables hass.states.async_set("pyscript.f1var1", 0) # try some values that shouldn't work, then one that does hass.states.async_set("pyscript.f1var1", "string") hass.states.async_set("pyscript.f1var1", 1) assert literal_eval(await wait_until_done(notify_q)) == [ seq_num, "pyscript.f1var1", 1, ] assert "func1 var = pyscript.f1var1, value = 1" in caplog.text next_source = source1 # # now reload the other source file # scripts = [ "/some/config/dir/pyscript/hello.py", ] integration = loader.Integration( hass, "config.custom_components.pyscript", pathlib.Path("config/custom_components/pyscript"), { "name": "pyscript", "dependencies": [], "requirements": [], "domain": "automation", }, ) with patch( "homeassistant.loader.async_get_integration", return_value=integration, ), patch("config.custom_components.pyscript.os.path.isdir", return_value=True), patch( "config.custom_components.pyscript.glob.iglob", return_value=scripts), patch( "config.custom_components.pyscript.open", mock_open(read_data=next_source), create=True, ), patch( "config.custom_components.pyscript.trigger.dt_now", return_value=now): await hass.services.async_call("pyscript", "reload", {}, blocking=True)
def test_integration_properties(hass): """Test integration properties.""" integration = loader.Integration( hass, "homeassistant.components.hue", None, { "name": "Philips Hue", "domain": "hue", "dependencies": ["test-dep"], "requirements": ["test-req==1.0.0"], "zeroconf": ["_hue._tcp.local."], "homekit": { "models": ["BSB002"] }, "ssdp": [ { "manufacturer": "Royal Philips Electronics", "modelName": "Philips hue bridge 2012", }, { "manufacturer": "Royal Philips Electronics", "modelName": "Philips hue bridge 2015", }, { "manufacturer": "Signify", "modelName": "Philips hue bridge 2015" }, ], }, ) assert integration.name == "Philips Hue" assert integration.domain == "hue" assert integration.homekit == {"models": ["BSB002"]} assert integration.zeroconf == ["_hue._tcp.local."] assert integration.ssdp == [ { "manufacturer": "Royal Philips Electronics", "modelName": "Philips hue bridge 2012", }, { "manufacturer": "Royal Philips Electronics", "modelName": "Philips hue bridge 2015", }, { "manufacturer": "Signify", "modelName": "Philips hue bridge 2015" }, ] assert integration.dependencies == ["test-dep"] assert integration.requirements == ["test-req==1.0.0"] assert integration.is_built_in is True integration = loader.Integration( hass, "custom_components.hue", None, { "name": "Philips Hue", "domain": "hue", "dependencies": ["test-dep"], "requirements": ["test-req==1.0.0"], }, ) assert integration.is_built_in is False assert integration.homekit is None assert integration.zeroconf is None assert integration.ssdp is None