async def test_login_flow_validates(data, hass): """Test login flow.""" data.add_auth("test-user", "test-pass") await data.async_save() provider = hass_auth.HassAuthProvider( hass, auth_store.AuthStore(hass), {"type": "homeassistant"} ) flow = await provider.async_login_flow({}) result = await flow.async_step_init() assert result["type"] == data_entry_flow.FlowResultType.FORM result = await flow.async_step_init( {"username": "******", "password": "******"} ) assert result["type"] == data_entry_flow.FlowResultType.FORM assert result["errors"]["base"] == "invalid_auth" result = await flow.async_step_init( {"username": "******", "password": "******"} ) assert result["type"] == data_entry_flow.FlowResultType.FORM assert result["errors"]["base"] == "invalid_auth" result = await flow.async_step_init( {"username": "******", "password": "******"} ) assert result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY assert result["data"]["username"] == "test-USER"
async def test_saving_loading(hass, hass_storage): """Test storing and saving data. Creates one of each type that we store to test we restore correctly. """ manager = await auth.auth_manager_from_config( hass, [{ 'type': 'insecure_example', 'users': [{ 'username': '******', 'password': '******', }] }], []) step = await manager.login_flow.async_init(('insecure_example', None)) step = await manager.login_flow.async_configure(step['flow_id'], { 'username': '******', 'password': '******', }) user = step['result'] await manager.async_activate_user(user) await manager.async_create_refresh_token(user, CLIENT_ID) await flush_store(manager._store._store) store2 = auth_store.AuthStore(hass) users = await store2.async_get_users() assert len(users) == 1 assert users[0] == user
async def test_login_flow_validates(data, hass): """Test login flow.""" data.add_auth('test-user', 'test-pass') await data.async_save() provider = hass_auth.HassAuthProvider(hass, auth_store.AuthStore(hass), {'type': 'homeassistant'}) flow = await provider.async_login_flow({}) result = await flow.async_step_init() assert result['type'] == data_entry_flow.RESULT_TYPE_FORM result = await flow.async_step_init({ 'username': '******', 'password': '******', }) assert result['type'] == data_entry_flow.RESULT_TYPE_FORM assert result['errors']['base'] == 'invalid_auth' result = await flow.async_step_init({ 'username': '******', 'password': '******', }) assert result['type'] == data_entry_flow.RESULT_TYPE_FORM assert result['errors']['base'] == 'invalid_auth' result = await flow.async_step_init({ 'username': '******', 'password': '******', }) assert result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result['data']['username'] == 'test-user'
async def test_legacy_login_flow_validates(legacy_data, hass): """Test in legacy mode login flow.""" legacy_data.add_auth("test-user", "test-pass") await legacy_data.async_save() provider = hass_auth.HassAuthProvider( hass, auth_store.AuthStore(hass), {"type": "homeassistant"} ) flow = await provider.async_login_flow({}) result = await flow.async_step_init() assert result["type"] == data_entry_flow.RESULT_TYPE_FORM result = await flow.async_step_init( {"username": "******", "password": "******"} ) assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["errors"]["base"] == "invalid_auth" result = await flow.async_step_init( {"username": "******", "password": "******"} ) assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["errors"]["base"] == "invalid_auth" result = await flow.async_step_init( {"username": "******", "password": "******"} ) assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result["data"]["username"] == "test-user"
def async_test_home_assistant(loop): """Return a Home Assistant object pointing at test config dir.""" hass = ha.HomeAssistant(loop) hass.config.async_load = Mock() store = auth_store.AuthStore(hass) hass.auth = auth.AuthManager(hass, store, {}) ensure_auth_manager_loaded(hass.auth) INSTANCES.append(hass) orig_async_add_job = hass.async_add_job def async_add_job(target, *args): """Add a magic mock.""" if isinstance(target, Mock): return mock_coro(target(*args)) return orig_async_add_job(target, *args) hass.async_add_job = async_add_job hass.config.location_name = 'test home' hass.config.config_dir = get_test_config_dir() hass.config.latitude = 32.87336 hass.config.longitude = -117.22743 hass.config.elevation = 0 hass.config.time_zone = date_util.get_time_zone('US/Pacific') hass.config.units = METRIC_SYSTEM hass.config.skip_pip = True hass.config_entries = config_entries.ConfigEntries(hass, {}) hass.config_entries._entries = [] hass.config_entries._store._async_ensure_stop_listener = lambda: None hass.state = ha.CoreState.running # Mock async_start orig_start = hass.async_start @asyncio.coroutine def mock_async_start(): """Start the mocking.""" # We only mock time during tests and we want to track tasks with patch('homeassistant.core._async_create_timer'), \ patch.object(hass, 'async_stop_track_tasks'): yield from orig_start() hass.async_start = mock_async_start @ha.callback def clear_instance(event): """Clear global instance.""" INSTANCES.remove(hass) hass.bus.async_listen_once(EVENT_HOMEASSISTANT_CLOSE, clear_instance) return hass
async def test_saving_loading(hass, hass_storage): """Test storing and saving data. Creates one of each type that we store to test we restore correctly. """ manager = await auth.auth_manager_from_config( hass, [{ "type": "insecure_example", "users": [{ "username": "******", "password": "******" }], }], [], ) step = await manager.login_flow.async_init(("insecure_example", None)) step = await manager.login_flow.async_configure(step["flow_id"], { "username": "******", "password": "******" }) credential = step["result"] user = await manager.async_get_or_create_user(credential) await manager.async_activate_user(user) # the first refresh token will be used to create access token refresh_token = await manager.async_create_refresh_token( user, CLIENT_ID, credential=credential) manager.async_create_access_token(refresh_token, "192.168.0.1") # the second refresh token will not be used await manager.async_create_refresh_token(user, "dummy-client", credential=credential) await flush_store(manager._store._store) store2 = auth_store.AuthStore(hass) users = await store2.async_get_users() assert len(users) == 1 assert users[0].permissions == user.permissions assert users[0] == user assert len(users[0].refresh_tokens) == 2 for r_token in users[0].refresh_tokens.values(): if r_token.client_id == CLIENT_ID: # verify the first refresh token assert r_token.last_used_at is not None assert r_token.last_used_ip == "192.168.0.1" elif r_token.client_id == "dummy-client": # verify the second refresh token assert r_token.last_used_at is None assert r_token.last_used_ip is None else: assert False, "Unknown client_id: %s" % r_token.client_id
async def test_system_groups_store_id_and_name(hass, hass_storage): """Test that for system groups we store the ID and name. Name is stored so that we remain backwards compat with < 0.82. """ store = auth_store.AuthStore(hass) await store._async_load() data = store._data_to_save() assert len(data["users"]) == 0 assert data["groups"] == [ {"id": auth_store.GROUP_ID_ADMIN, "name": auth_store.GROUP_NAME_ADMIN}, {"id": auth_store.GROUP_ID_USER, "name": auth_store.GROUP_NAME_USER}, {"id": auth_store.GROUP_ID_READ_ONLY, "name": auth_store.GROUP_NAME_READ_ONLY}, ]
async def test_system_groups_only_store_id(hass, hass_storage): """Test that for system groups we only store the ID.""" store = auth_store.AuthStore(hass) await store._async_load() data = store._data_to_save() assert len(data['users']) == 0 assert data['groups'] == [ { 'id': auth_store.GROUP_ID_ADMIN }, { 'id': auth_store.GROUP_ID_READ_ONLY }, ]
async def test_loading_empty_data(hass, hass_storage): """Test we correctly load with no existing data.""" store = auth_store.AuthStore(hass) groups = await store.async_get_groups() assert len(groups) == 2 admin_group = groups[0] assert admin_group.name == auth_store.GROUP_NAME_ADMIN assert admin_group.system_generated assert admin_group.id == auth_store.GROUP_ID_ADMIN read_group = groups[1] assert read_group.name == auth_store.GROUP_NAME_READ_ONLY assert read_group.system_generated assert read_group.id == auth_store.GROUP_ID_READ_ONLY users = await store.async_get_users() assert len(users) == 0
async def test_loading_race_condition(hass): """Test only one storage load called when concurrent loading occurred .""" store = auth_store.AuthStore(hass) with patch("homeassistant.helpers.entity_registry.async_get_registry" ) as mock_ent_registry, patch( "homeassistant.helpers.device_registry.async_get_registry" ) as mock_dev_registry, patch( "homeassistant.helpers.storage.Store.async_load", return_value=None) as mock_load: results = await asyncio.gather(store.async_get_users(), store.async_get_users()) mock_ent_registry.assert_called_once_with(hass) mock_dev_registry.assert_called_once_with(hass) mock_load.assert_called_once_with() assert results[0] == results[1]
async def test_saving_loading(hass, hass_storage): """Test storing and saving data. Creates one of each type that we store to test we restore correctly. """ manager = await auth.auth_manager_from_config( hass, [{ 'type': 'insecure_example', 'users': [{ 'username': '******', 'password': '******', }] }], []) step = await manager.login_flow.async_init(('insecure_example', None)) step = await manager.login_flow.async_configure(step['flow_id'], { 'username': '******', 'password': '******', }) user = step['result'] await manager.async_activate_user(user) # the first refresh token will be used to create access token refresh_token = await manager.async_create_refresh_token(user, CLIENT_ID) manager.async_create_access_token(refresh_token, '192.168.0.1') # the second refresh token will not be used await manager.async_create_refresh_token(user, 'dummy-client') await flush_store(manager._store._store) store2 = auth_store.AuthStore(hass) users = await store2.async_get_users() assert len(users) == 1 assert users[0].permissions == user.permissions assert users[0] == user assert len(users[0].refresh_tokens) == 2 for r_token in users[0].refresh_tokens.values(): if r_token.client_id == CLIENT_ID: # verify the first refresh token assert r_token.last_used_at is not None assert r_token.last_used_ip == '192.168.0.1' elif r_token.client_id == 'dummy-client': # verify the second refresh token assert r_token.last_used_at is None assert r_token.last_used_ip is None else: assert False, 'Unknown client_id: %s' % r_token.client_id
async def test_system_groups_store_id_and_name(hass, hass_storage): """Test that for system groups we store the ID and name. Name is stored so that we remain backwards compat with < 0.82. """ store = auth_store.AuthStore(hass) await store._async_load() data = store._data_to_save() assert len(data['users']) == 0 assert data['groups'] == [ { 'id': auth_store.GROUP_ID_ADMIN, 'name': auth_store.GROUP_NAME_ADMIN, }, { 'id': auth_store.GROUP_ID_READ_ONLY, 'name': auth_store.GROUP_NAME_READ_ONLY, }, ]
async def test_race_condition_in_data_loading(hass): """Test race condition in the hass_auth.Data loading. Ref issue: https://github.com/home-assistant/core/issues/21569 """ counter = 0 async def mock_load(_): """Mock of homeassistant.helpers.storage.Store.async_load.""" nonlocal counter counter += 1 await asyncio.sleep(0) provider = hass_auth.HassAuthProvider( hass, auth_store.AuthStore(hass), {"type": "homeassistant"} ) with patch("homeassistant.helpers.storage.Store.async_load", new=mock_load): task1 = provider.async_validate_login("user", "pass") task2 = provider.async_validate_login("user", "pass") results = await asyncio.gather(task1, task2, return_exceptions=True) assert counter == 1 assert isinstance(results[0], hass_auth.InvalidAuth) # results[1] will be a TypeError if race condition occurred assert isinstance(results[1], hass_auth.InvalidAuth)
async def async_test_home_assistant(loop): """Return a Home Assistant object pointing at test config dir.""" hass = ha.HomeAssistant() store = auth_store.AuthStore(hass) hass.auth = auth.AuthManager(hass, store, {}, {}) ensure_auth_manager_loaded(hass.auth) INSTANCES.append(hass) orig_async_add_job = hass.async_add_job orig_async_add_executor_job = hass.async_add_executor_job orig_async_create_task = hass.async_create_task def async_add_job(target, *args): """Add job.""" check_target = target while isinstance(check_target, ft.partial): check_target = check_target.func if isinstance(check_target, Mock) and not isinstance(target, AsyncMock): fut = asyncio.Future() fut.set_result(target(*args)) return fut return orig_async_add_job(target, *args) def async_add_executor_job(target, *args): """Add executor job.""" check_target = target while isinstance(check_target, ft.partial): check_target = check_target.func if isinstance(check_target, Mock): fut = asyncio.Future() fut.set_result(target(*args)) return fut return orig_async_add_executor_job(target, *args) def async_create_task(coroutine): """Create task.""" if isinstance(coroutine, Mock) and not isinstance(coroutine, AsyncMock): fut = asyncio.Future() fut.set_result(None) return fut return orig_async_create_task(coroutine) hass.async_add_job = async_add_job hass.async_add_executor_job = async_add_executor_job hass.async_create_task = async_create_task hass.data[loader.DATA_CUSTOM_COMPONENTS] = {} hass.config.location_name = "test home" hass.config.config_dir = get_test_config_dir() hass.config.latitude = 32.87336 hass.config.longitude = -117.22743 hass.config.elevation = 0 hass.config.time_zone = date_util.get_time_zone("US/Pacific") hass.config.units = METRIC_SYSTEM hass.config.media_dirs = {"local": get_test_config_dir("media")} hass.config.skip_pip = True hass.config_entries = config_entries.ConfigEntries(hass, {}) hass.config_entries._entries = [] hass.config_entries._store._async_ensure_stop_listener = lambda: None hass.state = ha.CoreState.running # Mock async_start orig_start = hass.async_start async def mock_async_start(): """Start the mocking.""" # We only mock time during tests and we want to track tasks with patch("homeassistant.core._async_create_timer"), patch.object( hass, "async_stop_track_tasks"): await orig_start() hass.async_start = mock_async_start @ha.callback def clear_instance(event): """Clear global instance.""" INSTANCES.remove(hass) hass.bus.async_listen_once(EVENT_HOMEASSISTANT_CLOSE, clear_instance) return hass
async def test_loading_all_access_group_data_format(hass, hass_storage): """Test we correctly load old data with single group.""" hass_storage[auth_store.STORAGE_KEY] = { 'version': 1, 'data': { 'credentials': [], 'users': [ { "id": "user-id", "is_active": True, "is_owner": True, "name": "Paulus", "system_generated": False, 'group_ids': ['abcd-all-access'] }, { "id": "system-id", "is_active": True, "is_owner": True, "name": "Hass.io", "system_generated": True, } ], "groups": [ { "id": "abcd-all-access", "name": "All Access", } ], "refresh_tokens": [ { "access_token_expiration": 1800.0, "client_id": "http://localhost:8123/", "created_at": "2018-10-03T13:43:19.774637+00:00", "id": "user-token-id", "jwt_key": "some-key", "last_used_at": "2018-10-03T13:43:19.774712+00:00", "token": "some-token", "user_id": "user-id" }, { "access_token_expiration": 1800.0, "client_id": None, "created_at": "2018-10-03T13:43:19.774637+00:00", "id": "system-token-id", "jwt_key": "some-key", "last_used_at": "2018-10-03T13:43:19.774712+00:00", "token": "some-token", "user_id": "system-id" }, { "access_token_expiration": 1800.0, "client_id": "http://localhost:8123/", "created_at": "2018-10-03T13:43:19.774637+00:00", "id": "hidden-because-no-jwt-id", "last_used_at": "2018-10-03T13:43:19.774712+00:00", "token": "some-token", "user_id": "user-id" }, ] } } store = auth_store.AuthStore(hass) groups = await store.async_get_groups() assert len(groups) == 3 admin_group = groups[0] assert admin_group.name == auth_store.GROUP_NAME_ADMIN assert admin_group.system_generated assert admin_group.id == auth_store.GROUP_ID_ADMIN read_group = groups[1] assert read_group.name == auth_store.GROUP_NAME_READ_ONLY assert read_group.system_generated assert read_group.id == auth_store.GROUP_ID_READ_ONLY user_group = groups[2] assert user_group.name == auth_store.GROUP_NAME_USER assert user_group.system_generated assert user_group.id == auth_store.GROUP_ID_USER users = await store.async_get_users() assert len(users) == 2 owner, system = users assert owner.system_generated is False assert owner.groups == [admin_group] assert len(owner.refresh_tokens) == 1 owner_token = list(owner.refresh_tokens.values())[0] assert owner_token.id == 'user-token-id' assert system.system_generated is True assert system.groups == [] assert len(system.refresh_tokens) == 1 system_token = list(system.refresh_tokens.values())[0] assert system_token.id == 'system-token-id'
async def async_test_home_assistant(loop, load_registries=True): """Return a Home Assistant object pointing at test config dir.""" hass = ha.HomeAssistant() store = auth_store.AuthStore(hass) hass.auth = auth.AuthManager(hass, store, {}, {}) ensure_auth_manager_loaded(hass.auth) INSTANCES.append(hass) orig_async_add_job = hass.async_add_job orig_async_add_executor_job = hass.async_add_executor_job orig_async_create_task = hass.async_create_task def async_add_job(target, *args): """Add job.""" check_target = target while isinstance(check_target, ft.partial): check_target = check_target.func if isinstance(check_target, Mock) and not isinstance(target, AsyncMock): fut = asyncio.Future() fut.set_result(target(*args)) return fut return orig_async_add_job(target, *args) def async_add_executor_job(target, *args): """Add executor job.""" check_target = target while isinstance(check_target, ft.partial): check_target = check_target.func if isinstance(check_target, Mock): fut = asyncio.Future() fut.set_result(target(*args)) return fut return orig_async_add_executor_job(target, *args) def async_create_task(coroutine): """Create task.""" if isinstance(coroutine, Mock) and not isinstance(coroutine, AsyncMock): fut = asyncio.Future() fut.set_result(None) return fut return orig_async_create_task(coroutine) async def async_wait_for_task_count(self, max_remaining_tasks: int = 0) -> None: """Block until at most max_remaining_tasks remain. Based on HomeAssistant.async_block_till_done """ # To flush out any call_soon_threadsafe await asyncio.sleep(0) start_time: float | None = None while len(self._pending_tasks) > max_remaining_tasks: pending: Collection[Awaitable[Any]] = [ task for task in self._pending_tasks if not task.done() ] self._pending_tasks.clear() if len(pending) > max_remaining_tasks: remaining_pending = await self._await_count_and_log_pending( pending, max_remaining_tasks=max_remaining_tasks) self._pending_tasks.extend(remaining_pending) if start_time is None: # Avoid calling monotonic() until we know # we may need to start logging blocked tasks. start_time = 0 elif start_time == 0: # If we have waited twice then we set the start # time start_time = monotonic() elif monotonic() - start_time > BLOCK_LOG_TIMEOUT: # We have waited at least three loops and new tasks # continue to block. At this point we start # logging all waiting tasks. for task in pending: _LOGGER.debug("Waiting for task: %s", task) else: self._pending_tasks.extend(pending) await asyncio.sleep(0) async def _await_count_and_log_pending( self, pending: Collection[Awaitable[Any]], max_remaining_tasks: int = 0) -> Collection[Awaitable[Any]]: """Block at most max_remaining_tasks remain and log tasks that take a long time. Based on HomeAssistant._await_and_log_pending """ wait_time = 0 return_when = asyncio.ALL_COMPLETED if max_remaining_tasks: return_when = asyncio.FIRST_COMPLETED while len(pending) > max_remaining_tasks: _, pending = await asyncio.wait(pending, timeout=BLOCK_LOG_TIMEOUT, return_when=return_when) if not pending or max_remaining_tasks: return pending wait_time += BLOCK_LOG_TIMEOUT for task in pending: _LOGGER.debug("Waited %s seconds for task: %s", wait_time, task) return [] hass.async_add_job = async_add_job hass.async_add_executor_job = async_add_executor_job hass.async_create_task = async_create_task hass.async_wait_for_task_count = types.MethodType( async_wait_for_task_count, hass) hass._await_count_and_log_pending = types.MethodType( _await_count_and_log_pending, hass) hass.data[loader.DATA_CUSTOM_COMPONENTS] = {} hass.config.location_name = "test home" hass.config.config_dir = get_test_config_dir() hass.config.latitude = 32.87336 hass.config.longitude = -117.22743 hass.config.elevation = 0 hass.config.time_zone = "US/Pacific" hass.config.units = METRIC_SYSTEM hass.config.media_dirs = {"local": get_test_config_dir("media")} hass.config.skip_pip = True hass.config_entries = config_entries.ConfigEntries(hass, {}) hass.config_entries._entries = {} hass.config_entries._store._async_ensure_stop_listener = lambda: None # Load the registries if load_registries: await asyncio.gather( device_registry.async_load(hass), entity_registry.async_load(hass), area_registry.async_load(hass), ) await hass.async_block_till_done() hass.state = ha.CoreState.running # Mock async_start orig_start = hass.async_start async def mock_async_start(): """Start the mocking.""" # We only mock time during tests and we want to track tasks with patch("homeassistant.core._async_create_timer"), patch.object( hass, "async_stop_track_tasks"): await orig_start() hass.async_start = mock_async_start @ha.callback def clear_instance(event): """Clear global instance.""" INSTANCES.remove(hass) hass.bus.async_listen_once(EVENT_HOMEASSISTANT_CLOSE, clear_instance) return hass
async def test_loading_old_data_format(hass, hass_storage): """Test we correctly load an old data format.""" hass_storage[auth_store.STORAGE_KEY] = { 'version': 1, 'data': { 'credentials': [], 'users': [ { "id": "user-id", "is_active": True, "is_owner": True, "name": "Paulus", "system_generated": False, }, { "id": "system-id", "is_active": True, "is_owner": True, "name": "Hass.io", "system_generated": True, } ], "refresh_tokens": [ { "access_token_expiration": 1800.0, "client_id": "http://localhost:8123/", "created_at": "2018-10-03T13:43:19.774637+00:00", "id": "user-token-id", "jwt_key": "some-key", "last_used_at": "2018-10-03T13:43:19.774712+00:00", "token": "some-token", "user_id": "user-id" }, { "access_token_expiration": 1800.0, "client_id": None, "created_at": "2018-10-03T13:43:19.774637+00:00", "id": "system-token-id", "jwt_key": "some-key", "last_used_at": "2018-10-03T13:43:19.774712+00:00", "token": "some-token", "user_id": "system-id" }, { "access_token_expiration": 1800.0, "client_id": "http://localhost:8123/", "created_at": "2018-10-03T13:43:19.774637+00:00", "id": "hidden-because-no-jwt-id", "last_used_at": "2018-10-03T13:43:19.774712+00:00", "token": "some-token", "user_id": "user-id" }, ] } } store = auth_store.AuthStore(hass) groups = await store.async_get_groups() assert len(groups) == 1 group = groups[0] assert group.name == "All Access" users = await store.async_get_users() assert len(users) == 2 owner, system = users assert owner.system_generated is False assert owner.groups == [group] assert len(owner.refresh_tokens) == 1 owner_token = list(owner.refresh_tokens.values())[0] assert owner_token.id == 'user-token-id' assert system.system_generated is True assert system.groups == [] assert len(system.refresh_tokens) == 1 system_token = list(system.refresh_tokens.values())[0] assert system_token.id == 'system-token-id'
def async_test_home_assistant(loop): """Return a Home Assistant object pointing at test config dir.""" hass = ha.HomeAssistant(loop) hass.config.async_load = Mock() store = auth_store.AuthStore(hass) hass.auth = auth.AuthManager(hass, store, {}, {}) ensure_auth_manager_loaded(hass.auth) INSTANCES.append(hass) orig_async_add_job = hass.async_add_job orig_async_add_executor_job = hass.async_add_executor_job orig_async_create_task = hass.async_create_task def async_add_job(target, *args): """Add job.""" if isinstance(target, Mock): return mock_coro(target(*args)) return orig_async_add_job(target, *args) def async_add_executor_job(target, *args): """Add executor job.""" if isinstance(target, Mock): return mock_coro(target(*args)) return orig_async_add_executor_job(target, *args) def async_create_task(coroutine): """Create task.""" if isinstance(coroutine, Mock): return mock_coro() return orig_async_create_task(coroutine) hass.async_add_job = async_add_job hass.async_add_executor_job = async_add_executor_job hass.async_create_task = async_create_task hass.config.location_name = "test home" hass.config.latitude = 51.8391 hass.config.longitude = 5.8739 hass.config.elevation = 0 hass.config.time_zone = date_util.get_time_zone("Europe/Amsterdam") hass.config.units = METRIC_SYSTEM hass.config.skip_pip = True date_util.set_default_time_zone(hass.config.time_zone) hass.config_entries = config_entries.ConfigEntries(hass, {}) hass.config_entries._entries = [] hass.config_entries._store._async_ensure_stop_listener = lambda: None hass.state = ha.CoreState.running # Mock async_start orig_start = hass.async_start @asyncio.coroutine def mock_async_start(): """Start the mocking.""" # We only mock time during tests and we want to track tasks with patch("homeassistant.core._async_create_timer"), patch.object( hass, "async_stop_track_tasks"): yield from orig_start() hass.async_start = mock_async_start @ha.callback def clear_instance(event): """Clear global instance.""" INSTANCES.remove(hass) hass.bus.async_listen_once(EVENT_HOMEASSISTANT_CLOSE, clear_instance) return hass
def store(hass): """Mock store.""" return auth_store.AuthStore(hass)
async def async_test_home_assistant(loop): hass = ha.HomeAssistant(loop) store = auth_store.AuthStore(hass) hass.auth = auth.AuthManager(hass, store, {}, {}) hass.config.config_dir = get_test_config_dir() return hass