async def mock_supervisor_fixture(hass, aioclient_mock): """Mock supervisor.""" aioclient_mock.post("http://127.0.0.1/homeassistant/options", json={"result": "ok"}) aioclient_mock.post("http://127.0.0.1/supervisor/options", json={"result": "ok"}) with patch.dict(os.environ, {"HASSIO": "127.0.0.1"}), patch( "homeassistant.components.hassio.HassIO.is_connected", return_value=True, ), patch( "homeassistant.components.hassio.HassIO.get_info", return_value={}, ), patch( "homeassistant.components.hassio.HassIO.get_host_info", return_value={}, ), patch( "homeassistant.components.hassio.HassIO.get_supervisor_info", return_value={}, ), patch( "homeassistant.components.hassio.HassIO.get_os_info", return_value={}, ), patch( "homeassistant.components.hassio.HassIO.get_ingress_panels", return_value={"panels": {}}, ), patch.dict(os.environ, {"HASSIO_TOKEN": "123456"}): yield
async def test_load_hassio(hass): """Test that we load Hass.io component.""" with patch.dict(os.environ, {}, clear=True): assert bootstrap._get_domains(hass, {}) == set() with patch.dict(os.environ, {"HASSIO": "1"}): assert bootstrap._get_domains(hass, {}) == {"hassio"}
async def test_two_step_flow(hass, client): """Test we can finish a two step flow.""" mock_integration( hass, MockModule("test", async_setup_entry=AsyncMock(return_value=True))) mock_entity_platform(hass, "config_flow.test", None) class TestFlow(core_ce.ConfigFlow): VERSION = 1 async def async_step_user(self, user_input=None): return self.async_show_form(step_id="account", data_schema=vol.Schema( {"user_title": str})) async def async_step_account(self, user_input=None): return self.async_create_entry(title=user_input["user_title"], data={"secret": "account_token"}) with patch.dict(HANDLERS, {"test": TestFlow}): resp = await client.post("/api/config/config_entries/flow", json={"handler": "test"}) assert resp.status == 200 data = await resp.json() flow_id = data.pop("flow_id") assert data == { "type": "form", "handler": "test", "step_id": "account", "data_schema": [{ "name": "user_title", "type": "string" }], "description_placeholders": None, "errors": None, } with patch.dict(HANDLERS, {"test": TestFlow}): resp = await client.post( f"/api/config/config_entries/flow/{flow_id}", json={"user_title": "user-title"}, ) assert resp.status == 200 entries = hass.config_entries.async_entries("test") assert len(entries) == 1 data = await resp.json() data.pop("flow_id") assert data == { "handler": "test", "type": "create_entry", "title": "user-title", "version": 1, "result": entries[0].entry_id, "description": None, "description_placeholders": None, }
def hassio_env_fixture(): """Fixture to inject hassio env.""" with patch.dict(os.environ, {"HASSIO": "127.0.0.1"}), patch( "homeassistant.components.hassio.HassIO.is_connected", return_value={ "result": "ok", "data": {} }, ), patch.dict(os.environ, {"HASSIO_TOKEN": "123456"}): yield
async def test_setup_hassio_no_additional_data(hass, aioclient_mock): """Test setup with API push default data.""" with patch.dict(os.environ, MOCK_ENVIRON), patch.dict( os.environ, {"HASSIO_TOKEN": "123456"} ): result = await async_setup_component(hass, "hassio", {"hassio": {}}) assert result assert aioclient_mock.call_count == 6 assert aioclient_mock.mock_calls[-1][3]["X-Hassio-Key"] == "123456"
def hassio_env(): """Fixture to inject hassio env.""" with patch.dict(os.environ, {"HASSIO": "127.0.0.1"}), patch( "homeassistant.components.hassio.HassIO.is_connected", return_value={"result": "ok", "data": {}}, ), patch.dict(os.environ, {"HASSIO_TOKEN": "123456"}), patch( "homeassistant.components.hassio.HassIO.get_info", Mock(side_effect=HassioAPIError()), ): yield
async def test_websocket_status(hass, hass_ws_client, mock_cloud_fixture, mock_cloud_login): """Test querying the status.""" hass.data[DOMAIN].iot.state = STATE_CONNECTED client = await hass_ws_client(hass) with patch.dict( "homeassistant.components.google_assistant.const.DOMAIN_TO_GOOGLE_TYPES", {"light": None}, clear=True, ), patch.dict( "homeassistant.components.alexa.entities.ENTITY_ADAPTERS", {"switch": None}, clear=True, ): await client.send_json({"id": 5, "type": "cloud/status"}) response = await client.receive_json() assert response["result"] == { "logged_in": True, "email": "*****@*****.**", "cloud": "connected", "prefs": { "alexa_enabled": True, "cloudhooks": {}, "google_enabled": True, "google_entity_configs": {}, "google_secure_devices_pin": None, "google_default_expose": None, "alexa_default_expose": None, "alexa_entity_configs": {}, "alexa_report_state": False, "google_report_state": False, "remote_enabled": False, }, "alexa_entities": { "include_domains": [], "include_entity_globs": [], "include_entities": ["light.kitchen", "switch.ac"], "exclude_domains": [], "exclude_entity_globs": [], "exclude_entities": [], }, "google_entities": { "include_domains": ["light"], "include_entity_globs": [], "include_entities": [], "exclude_domains": [], "exclude_entity_globs": [], "exclude_entities": [], }, "remote_domain": None, "remote_connected": False, "remote_certificate": None, }
async def test_homekit_match_full(hass, mock_zeroconf): """Test configured options for a device are loaded via config entry.""" with patch.dict( zc_gen.ZEROCONF, {zeroconf.HOMEKIT_TYPE: ["homekit_controller"]}, clear=True), patch.object( hass.config_entries.flow, "async_init") as mock_config_flow, patch.object( zeroconf, "HaServiceBrowser", side_effect=service_update_mock) as mock_service_browser: mock_zeroconf.get_service_info.side_effect = get_homekit_info_mock( "BSB002", HOMEKIT_STATUS_UNPAIRED) assert await async_setup_component(hass, zeroconf.DOMAIN, {zeroconf.DOMAIN: {}}) hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED) await hass.async_block_till_done() homekit_mock = get_homekit_info_mock("BSB002", HOMEKIT_STATUS_UNPAIRED) info = homekit_mock("_hap._tcp.local.", "BSB002._hap._tcp.local.") import pprint pprint.pprint(["homekit", info]) assert len(mock_service_browser.mock_calls) == 1 assert len(mock_config_flow.mock_calls) == 1 assert mock_config_flow.mock_calls[0][1][0] == "hue"
async def test_cloud_calling_handler(mock_iot_client, cloud_mock_iot): """Test we call handle message with correct info.""" conn = iot.CloudIoT(cloud_mock_iot) mock_iot_client.receive = AsyncMock( return_value=MagicMock( type=WSMsgType.text, json=MagicMock( return_value={ "msgid": "test-msg-id", "handler": "test-handler", "payload": "test-payload", } ), ) ) mock_handler = AsyncMock(return_value="response") mock_iot_client.send_json = AsyncMock() with patch.dict(iot.HANDLERS, {"test-handler": mock_handler}, clear=True): await conn.connect() await asyncio.sleep(0) # Check that we sent message to handler correctly assert len(mock_handler.mock_calls) == 1 cloud, payload = mock_handler.mock_calls[0][1] assert cloud is cloud_mock_iot assert payload == "test-payload" # Check that we forwarded response from handler to cloud assert len(mock_iot_client.send_json.mock_calls) == 1 assert mock_iot_client.send_json.mock_calls[0][1][0] == { "msgid": "test-msg-id", "payload": "response", }
async def test_setup_api_push_api_data_default(hass, aioclient_mock, hass_storage): """Test setup with API push default data.""" with patch.dict(os.environ, MOCK_ENVIRON): result = await async_setup_component(hass, "hassio", { "http": {}, "hassio": {} }) assert result assert aioclient_mock.call_count == 6 assert not aioclient_mock.mock_calls[1][2]["ssl"] assert aioclient_mock.mock_calls[1][2]["port"] == 8123 refresh_token = aioclient_mock.mock_calls[1][2]["refresh_token"] hassio_user = await hass.auth.async_get_user( hass_storage[STORAGE_KEY]["data"]["hassio_user"]) assert hassio_user is not None assert hassio_user.system_generated assert len(hassio_user.groups) == 1 assert hassio_user.groups[0].id == GROUP_ID_ADMIN for token in hassio_user.refresh_tokens.values(): if token.token == refresh_token: break else: assert False, "refresh token not found"
async def test_get_progress_flow_unauth(hass, client, hass_admin_user): """Test we can can't query the API for result of flow.""" mock_entity_platform(hass, "config_flow.test", None) class TestFlow(core_ce.ConfigFlow): async def async_step_user(self, user_input=None): schema = OrderedDict() schema[vol.Required("username")] = str schema[vol.Required("password")] = str return self.async_show_form( step_id="user", data_schema=schema, errors={"username": "******"}, ) with patch.dict(HANDLERS, {"test": TestFlow}): resp = await client.post("/api/config/config_entries/flow", json={"handler": "test"}) assert resp.status == 200 data = await resp.json() hass_admin_user.groups = [] resp2 = await client.get("/api/config/config_entries/flow/{}".format( data["flow_id"])) assert resp2.status == 401
async def test_get_progress_index(hass, hass_ws_client): """Test querying for the flows that are in progress.""" assert await async_setup_component(hass, "config", {}) mock_entity_platform(hass, "config_flow.test", None) ws_client = await hass_ws_client(hass) class TestFlow(core_ce.ConfigFlow): VERSION = 5 async def async_step_hassio(self, info): return await self.async_step_account() async def async_step_account(self, user_input=None): return self.async_show_form(step_id="account") with patch.dict(HANDLERS, {"test": TestFlow}): form = await hass.config_entries.flow.async_init( "test", context={"source": "hassio"}) await ws_client.send_json({ "id": 5, "type": "config_entries/flow/progress" }) response = await ws_client.receive_json() assert response["success"] assert response["result"] == [{ "flow_id": form["flow_id"], "handler": "test", "step_id": "account", "context": { "source": "hassio" }, }]
async def test_create_account(hass, client): """Test a flow that creates an account.""" mock_entity_platform(hass, "config_flow.test", None) mock_integration( hass, MockModule("test", async_setup_entry=AsyncMock(return_value=True))) class TestFlow(core_ce.ConfigFlow): VERSION = 1 async def async_step_user(self, user_input=None): return self.async_create_entry(title="Test Entry", data={"secret": "account_token"}) with patch.dict(HANDLERS, {"test": TestFlow}): resp = await client.post("/api/config/config_entries/flow", json={"handler": "test"}) assert resp.status == 200 entries = hass.config_entries.async_entries("test") assert len(entries) == 1 data = await resp.json() data.pop("flow_id") assert data == { "handler": "test", "title": "Test Entry", "type": "create_entry", "version": 1, "result": entries[0].entry_id, "description": None, "description_placeholders": None, }
async def test_mqtt_discovery_unsubscribe_once(hass, mqtt_client_mock, mqtt_mock): """Check MQTT integration discovery unsubscribe once.""" mock_entity_platform(hass, "config_flow.comp", None) entry = hass.config_entries.async_entries("mqtt")[0] mqtt_mock().connected = True with patch( "homeassistant.components.mqtt.discovery.async_get_mqtt", return_value={"comp": ["comp/discovery/#"]}, ): await async_start(hass, "homeassistant", entry) await hass.async_block_till_done() mqtt_client_mock.subscribe.assert_any_call("comp/discovery/#", 0) assert not mqtt_client_mock.unsubscribe.called class TestFlow(config_entries.ConfigFlow): """Test flow.""" async def async_step_mqtt(self, discovery_info): """Test mqtt step.""" return self.async_abort(reason="already_configured") with patch.dict(config_entries.HANDLERS, {"comp": TestFlow}): async_fire_mqtt_message(hass, "comp/discovery/bla/config", "") async_fire_mqtt_message(hass, "comp/discovery/bla/config", "") await hass.async_block_till_done() await hass.async_block_till_done() mqtt_client_mock.unsubscribe.assert_called_once_with( "comp/discovery/#")
async def test_access_from_supervisor_ip(remote_addr, bans, status, hass, aiohttp_client, hassio_env): """Test accessing to server from supervisor IP.""" app = web.Application() app["hass"] = hass async def unauth_handler(request): """Return a mock web response.""" raise HTTPUnauthorized app.router.add_get("/", unauth_handler) setup_bans(hass, app, 1) mock_real_ip(app)(remote_addr) with patch("homeassistant.components.http.ban.async_load_ip_bans_config", return_value=[]): client = await aiohttp_client(app) assert await async_setup_component(hass, "hassio", {"hassio": {}}) m_open = mock_open() with patch.dict(os.environ, {"SUPERVISOR": SUPERVISOR_IP}), patch( "homeassistant.components.http.ban.open", m_open, create=True): resp = await client.get("/") assert resp.status == 401 assert len(app[KEY_BANNED_IPS]) == bans assert m_open.call_count == bans # second request should be forbidden if banned resp = await client.get("/") assert resp.status == status assert len(app[KEY_BANNED_IPS]) == bans
async def test_zeroconf_no_match(hass, mock_zeroconf): """Test configured options for a device are loaded via config entry.""" def http_only_service_update_mock(zeroconf, services, handlers): """Call service update handler.""" handlers[0]( zeroconf, "_http._tcp.local.", "somethingelse._http._tcp.local.", ServiceStateChange.Added, ) with patch.dict( zc_gen.ZEROCONF, {"_http._tcp.local.": [{"domain": "shelly", "name": "shelly*"}]}, clear=True, ), patch.object( hass.config_entries.flow, "async_init" ) as mock_config_flow, patch.object( zeroconf, "HaServiceBrowser", side_effect=http_only_service_update_mock ) as mock_service_browser: mock_zeroconf.get_service_info.side_effect = get_zeroconf_info_mock( "FFAADDCC11DD" ) assert await async_setup_component(hass, zeroconf.DOMAIN, {zeroconf.DOMAIN: {}}) hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED) await hass.async_block_till_done() assert len(mock_service_browser.mock_calls) == 1 assert len(mock_config_flow.mock_calls) == 0
async def test_connection_msg_for_handler_raising(mock_iot_client, cloud_mock_iot): """Test we sent error when handler raises exception.""" conn = iot.CloudIoT(cloud_mock_iot) mock_iot_client.receive = AsyncMock( return_value=MagicMock( type=WSMsgType.text, json=MagicMock( return_value={ "msgid": "test-msg-id", "handler": "test-handler", "payload": "test-payload", } ), ) ) mock_iot_client.send_json = AsyncMock() with patch.dict( iot.HANDLERS, {"test-handler": Mock(side_effect=Exception("Broken"))} ): await conn.connect() await asyncio.sleep(0) # Check that we sent the correct error assert len(mock_iot_client.send_json.mock_calls) == 1 assert mock_iot_client.send_json.mock_calls[0][1][0] == { "msgid": "test-msg-id", "error": "exception", }
def test_type_camera(type_name, entity_id, state, attrs): """Test if camera types are associated correctly.""" mock_type = Mock() with patch.dict(TYPES, {type_name: mock_type}): entity_state = State(entity_id, state, attrs) get_accessory(None, None, entity_state, 2, {}) assert mock_type.called
async def test_hassio_system_health_with_issues(hass, aioclient_mock): """Test hassio system health.""" aioclient_mock.get("http://127.0.0.1/info", json={ "result": "ok", "data": {} }) aioclient_mock.get("http://127.0.0.1/host/info", json={ "result": "ok", "data": {} }) aioclient_mock.get("http://127.0.0.1/os/info", json={ "result": "ok", "data": {} }) aioclient_mock.get("http://127.0.0.1/supervisor/ping", text="") aioclient_mock.get("https://version.home-assistant.io/stable.json", exc=ClientError) aioclient_mock.get("http://127.0.0.1/supervisor/info", json={ "result": "ok", "data": {} }) hass.config.components.add("hassio") with patch.dict(os.environ, MOCK_ENVIRON): assert await async_setup_component(hass, "system_health", {}) hass.data["hassio_info"] = {"channel": "stable"} hass.data["hassio_host_info"] = {} hass.data["hassio_os_info"] = {} hass.data["hassio_supervisor_info"] = { "healthy": False, "supported": False, } info = await get_system_health_info(hass, "hassio") for key, val in info.items(): if asyncio.iscoroutine(val): info[key] = await val assert info["healthy"] == { "error": "Unhealthy", "more_info": "/hassio/system", "type": "failed", } assert info["supported"] == { "error": "Unsupported", "more_info": "/hassio/system", "type": "failed", } assert info["version_api"] == { "error": "unreachable", "more_info": "/hassio/system", "type": "failed", }
def webhook_flow_conf(hass): """Register a handler.""" with patch.dict(config_entries.HANDLERS): config_entry_flow.register_webhook_flow("test_single", "Test Single", {}, False) config_entry_flow.register_webhook_flow( "test_multiple", "Test Multiple", {}, True ) yield {}
def mock_handlers(): """Mock config flows.""" class MockFlowHandler(config_entries.ConfigFlow): """Define a mock flow handler.""" VERSION = 1 with patch.dict(config_entries.HANDLERS, {"comp": MockFlowHandler}): yield
async def test_get_entries(hass, client): """Test get entries.""" with patch.dict(HANDLERS, clear=True): @HANDLERS.register("comp1") class Comp1ConfigFlow: """Config flow with options flow.""" @staticmethod @callback def async_get_options_flow(config, options): """Get options flow.""" pass hass.helpers.config_entry_flow.register_discovery_flow( "comp2", "Comp 2", lambda: None, core_ce.CONN_CLASS_ASSUMED) entry = MockConfigEntry( domain="comp1", title="Test 1", source="bla", connection_class=core_ce.CONN_CLASS_LOCAL_POLL, ) entry.supports_unload = True entry.add_to_hass(hass) MockConfigEntry( domain="comp2", title="Test 2", source="bla2", state=core_ce.ENTRY_STATE_LOADED, connection_class=core_ce.CONN_CLASS_ASSUMED, ).add_to_hass(hass) resp = await client.get("/api/config/config_entries/entry") assert resp.status == 200 data = await resp.json() for entry in data: entry.pop("entry_id") assert data == [ { "domain": "comp1", "title": "Test 1", "source": "bla", "state": "not_loaded", "connection_class": "local_poll", "supports_options": True, "supports_unload": True, }, { "domain": "comp2", "title": "Test 2", "source": "bla2", "state": "loaded", "connection_class": "assumed", "supports_options": False, "supports_unload": False, }, ]
async def test_setup_api_ping(hass, aioclient_mock): """Test setup with API ping.""" with patch.dict(os.environ, MOCK_ENVIRON): result = await async_setup_component(hass, "hassio", {}) assert result assert aioclient_mock.call_count == 6 assert hass.components.hassio.get_homeassistant_version() == "0.110.0" assert hass.components.hassio.is_hassio()
async def test_setup_api_ping(hass, aioclient_mock): """Test setup with API ping.""" with patch.dict(os.environ, MOCK_ENVIRON): result = await async_setup_component(hass, "hassio", {}) assert result assert aioclient_mock.call_count == 9 assert hass.components.hassio.get_core_info()["version_latest"] == "1.0.0" assert hass.components.hassio.is_hassio()
def test_customize_options(config, name): """Test with customized options.""" mock_type = Mock() conf = config.copy() conf[ATTR_INTERGRATION] = "platform_name" with patch.dict(TYPES, {"Light": mock_type}): entity_state = State("light.demo", "on") get_accessory(None, None, entity_state, 2, conf) mock_type.assert_called_with(None, None, name, "light.demo", 2, conf)
def setup_comp(): """Set up things to be run when tests are started.""" _base_mock = MagicMock() pykira = _base_mock.pykira pykira.__file__ = "test" _module_patcher = patch.dict("sys.modules", {"pykira": pykira}) _module_patcher.start() yield _module_patcher.stop()
def test_pysqlite_load_failure(stdlib_version, pysqlite3_version): """ Test that the internal import SQLite helper will throw an error when no compatible module can be found. """ if pysqlite3_version is not None: pysqlite3 = MagicMock() pysqlite3.sqlite_version_info = pysqlite3_version pysqlite3_patch = patch.dict(sys.modules, {"pysqlite3": pysqlite3}) else: pysqlite3_patch = patch.dict(sys.modules, {"pysqlite3": None}) with pysqlite3_patch, patch.object( sys.modules["sqlite3"], "sqlite_version_info", new=stdlib_version ): with pytest.raises(RuntimeError): zigpy.appdb._import_compatible_sqlite3(zigpy.appdb.MIN_SQLITE_VERSION)
def hassio_handler(hass, aioclient_mock): """Create mock hassio handler.""" async def get_client_session(): return hass.helpers.aiohttp_client.async_get_clientsession() websession = hass.loop.run_until_complete(get_client_session()) with patch.dict(os.environ, {"HASSIO_TOKEN": HASSIO_TOKEN}): yield HassIO(hass.loop, websession, "127.0.0.1")
def test_type_media_player(type_name, entity_id, state, attrs, config): """Test if media_player types are associated correctly.""" mock_type = Mock() with patch.dict(TYPES, {type_name: mock_type}): entity_state = State(entity_id, state, attrs) get_accessory(None, None, entity_state, 2, config) assert mock_type.called if config: assert mock_type.call_args[0][-1] == config
async def test_warn_when_cannot_connect(hass, caplog): """Fail warn when we cannot connect.""" with patch.dict(os.environ, MOCK_ENVIRON), patch( "homeassistant.components.hassio.HassIO.is_connected", return_value=None, ): result = await async_setup_component(hass, "hassio", {}) assert result assert hass.components.hassio.is_hassio() assert "Not connected with Hass.io / system to busy!" in caplog.text