async def test_setup_hass_safe_mode( mock_enable_logging, mock_is_virtual_env, mock_mount_local_lib_path, mock_ensure_config_exists, mock_process_ha_config_upgrade, loop, ): """Test it works.""" with patch( "homeassistant.components.browser.setup") as browser_setup, patch( "homeassistant.config_entries.ConfigEntries.async_domains", return_value=["browser"], ): hass = await bootstrap.async_setup_hass( runner.RuntimeConfig( config_dir=get_test_config_dir(), verbose=False, log_rotate_days=10, log_file="", log_no_color=False, skip_pip=True, safe_mode=True, ), ) assert "safe_mode" in hass.config.components assert len(mock_mount_local_lib_path.mock_calls) == 0 # Validate we didn't try to set up config entry. assert "browser" not in hass.config.components assert len(browser_setup.mock_calls) == 0
async def test_setup_hass_invalid_core_config( mock_enable_logging, mock_is_virtual_env, mock_mount_local_lib_path, mock_ensure_config_exists, mock_process_ha_config_upgrade, loop, ): """Test it works.""" with patch( "homeassistant.config.async_hass_config_yaml", return_value={"homeassistant": { "non-existing": 1 }}, ): hass = await bootstrap.async_setup_hass( runner.RuntimeConfig( config_dir=get_test_config_dir(), verbose=False, log_rotate_days=10, log_file="", log_no_color=False, skip_pip=True, safe_mode=False, ), ) assert "safe_mode" in hass.config.components
async def test_setup_hass_config_dir_nonexistent( mock_enable_logging, mock_is_virtual_env, mock_mount_local_lib_path, mock_ensure_config_exists, mock_process_ha_config_upgrade, loop, ): """Test it works.""" mock_ensure_config_exists.return_value = False assert ( await bootstrap.async_setup_hass( runner.RuntimeConfig( config_dir=get_test_config_dir(), verbose=False, log_rotate_days=10, log_file="", log_no_color=False, skip_pip=True, safe_mode=False, ), ) is None )
def main() -> int: """Start Home Assistant.""" validate_python() # Run a simple daemon runner process on Windows to handle restarts if os.name == "nt" and "--runner" not in sys.argv: nt_args = cmdline() + ["--runner"] while True: try: subprocess.check_call(nt_args) sys.exit(0) except KeyboardInterrupt: sys.exit(0) except subprocess.CalledProcessError as exc: if exc.returncode != RESTART_EXIT_CODE: sys.exit(exc.returncode) args = get_arguments() if args.script is not None: # pylint: disable=import-outside-toplevel from homeassistant import scripts return scripts.run(args.script) config_dir = os.path.abspath(os.path.join(os.getcwd(), args.config)) ensure_config_path(config_dir) # Daemon functions if args.pid_file: check_pid(args.pid_file) if args.daemon: daemonize() if args.pid_file: write_pid(args.pid_file) # pylint: disable=import-outside-toplevel from homeassistant import runner runtime_conf = runner.RuntimeConfig( config_dir=config_dir, verbose=args.verbose, log_rotate_days=args.log_rotate_days, log_file=args.log_file, log_no_color=args.log_no_color, skip_pip=args.skip_pip, safe_mode=args.safe_mode, debug=args.debug, open_ui=args.open_ui, ) exit_code = runner.run(runtime_conf) if exit_code == RESTART_EXIT_CODE and not args.runner: try_to_restart() return exit_code
async def test_setup_and_run_hass(hass, tmpdir): """Test we can setup and run.""" test_dir = tmpdir.mkdir("config") default_config = runner.RuntimeConfig(test_dir) with patch("homeassistant.bootstrap.async_setup_hass", return_value=hass), patch("threading._shutdown"), patch( "homeassistant.core.HomeAssistant.async_run") as mock_run: await runner.setup_and_run_hass(default_config) assert threading._shutdown == thread.deadlock_safe_shutdown assert mock_run.called
def test_run(hass, tmpdir): """Test we can run.""" test_dir = tmpdir.mkdir("config") default_config = runner.RuntimeConfig(test_dir) with patch.object(runner, "TASK_CANCELATION_TIMEOUT", 1), patch( "homeassistant.bootstrap.async_setup_hass", return_value=hass), patch("threading._shutdown"), patch( "homeassistant.core.HomeAssistant.async_run") as mock_run: runner.run(default_config) assert mock_run.called
async def test_setup_hass( mock_enable_logging, mock_is_virtual_env, mock_mount_local_lib_path, mock_ensure_config_exists, mock_process_ha_config_upgrade, caplog, loop, ): """Test it works.""" verbose = Mock() log_rotate_days = Mock() log_file = Mock() log_no_color = Mock() with patch( "homeassistant.config.async_hass_config_yaml", return_value={ "browser": {}, "frontend": {} }, ), patch.object(bootstrap, "LOG_SLOW_STARTUP_INTERVAL", 5000): hass = await bootstrap.async_setup_hass( runner.RuntimeConfig( config_dir=get_test_config_dir(), verbose=verbose, log_rotate_days=log_rotate_days, log_file=log_file, log_no_color=log_no_color, skip_pip=True, safe_mode=False, ), ) assert "Waiting on integrations to complete setup" not in caplog.text assert "browser" in hass.config.components assert "safe_mode" not in hass.config.components assert len(mock_enable_logging.mock_calls) == 1 assert mock_enable_logging.mock_calls[0][1] == ( hass, verbose, log_rotate_days, log_file, log_no_color, ) assert len(mock_mount_local_lib_path.mock_calls) == 1 assert len(mock_ensure_config_exists.mock_calls) == 1 assert len(mock_process_ha_config_upgrade.mock_calls) == 1 assert hass == core.async_get_hass()
def test_run_executor_shutdown_throws(hass, tmpdir): """Test we can run and we still shutdown if the executor shutdown throws.""" test_dir = tmpdir.mkdir("config") default_config = runner.RuntimeConfig(test_dir) with patch.object( runner, "TASK_CANCELATION_TIMEOUT", 1 ), pytest.raises(RuntimeError), patch( "homeassistant.bootstrap.async_setup_hass", return_value=hass ), patch("threading._shutdown"), patch( "homeassistant.runner.InterruptibleThreadPoolExecutor.shutdown", side_effect=RuntimeError, ) as mock_shutdown, patch( "homeassistant.core.HomeAssistant.async_run") as mock_run: runner.run(default_config) assert mock_shutdown.called assert mock_run.called
async def test_setup_safe_mode_if_no_frontend( mock_enable_logging, mock_is_virtual_env, mock_mount_local_lib_path, mock_ensure_config_exists, mock_process_ha_config_upgrade, loop, ): """Test we setup safe mode if frontend didn't load.""" verbose = Mock() log_rotate_days = Mock() log_file = Mock() log_no_color = Mock() with patch( "homeassistant.config.async_hass_config_yaml", return_value={ "homeassistant": { "internal_url": "http://192.168.1.100:8123", "external_url": "https://abcdef.ui.nabu.casa", }, "map": {}, "person": { "invalid": True }, }, ): hass = await bootstrap.async_setup_hass( runner.RuntimeConfig( config_dir=get_test_config_dir(), verbose=verbose, log_rotate_days=log_rotate_days, log_file=log_file, log_no_color=log_no_color, skip_pip=True, safe_mode=False, ), ) assert "safe_mode" in hass.config.components assert hass.config.config_dir == get_test_config_dir() assert hass.config.skip_pip assert hass.config.internal_url == "http://192.168.1.100:8123" assert hass.config.external_url == "https://abcdef.ui.nabu.casa"
async def test_setup_hass_takes_longer_than_log_slow_startup( mock_enable_logging, mock_is_virtual_env, mock_mount_local_lib_path, mock_ensure_config_exists, mock_process_ha_config_upgrade, caplog, loop, ): """Test it works.""" verbose = Mock() log_rotate_days = Mock() log_file = Mock() log_no_color = Mock() async def _async_setup_that_blocks_startup(*args, **kwargs): await asyncio.sleep(0.6) return True with patch( "homeassistant.config.async_hass_config_yaml", return_value={ "browser": {}, "frontend": {} }, ), patch.object(bootstrap, "LOG_SLOW_STARTUP_INTERVAL", 0.3), patch.object( bootstrap, "SLOW_STARTUP_CHECK_INTERVAL", 0.05), patch( "homeassistant.components.frontend.async_setup", side_effect=_async_setup_that_blocks_startup, ): await bootstrap.async_setup_hass( runner.RuntimeConfig( config_dir=get_test_config_dir(), verbose=verbose, log_rotate_days=log_rotate_days, log_file=log_file, log_no_color=log_no_color, skip_pip=True, safe_mode=False, ), ) assert "Waiting on integrations to complete setup" in caplog.text
def test_run_does_not_block_forever_with_shielded_task(hass, tmpdir, caplog): """Test we can shutdown and not block forever.""" test_dir = tmpdir.mkdir("config") default_config = runner.RuntimeConfig(test_dir) created_tasks = False async def _async_create_tasks(*_): nonlocal created_tasks async def async_raise(*_): try: await asyncio.sleep(2) except asyncio.CancelledError: raise Exception async def async_shielded(*_): try: await asyncio.sleep(2) except asyncio.CancelledError: await asyncio.sleep(2) asyncio.ensure_future(asyncio.shield(async_shielded())) asyncio.ensure_future(asyncio.sleep(2)) asyncio.ensure_future(async_raise()) await asyncio.sleep(0.1) created_tasks = True return 0 with patch.object(runner, "TASK_CANCELATION_TIMEOUT", 1), patch( "homeassistant.bootstrap.async_setup_hass", return_value=hass ), patch("threading._shutdown"), patch( "homeassistant.core.HomeAssistant.async_run", _async_create_tasks ): runner.run(default_config) assert created_tasks is True assert ( "Task could not be canceled and was still running after shutdown" in caplog.text )