async def test_detect_config_fail(hass, client): """Test detect config.""" with patch('homeassistant.util.location.async_detect_location_info', return_value=mock_coro( location.LocationInfo( ip=None, country_code=None, country_name=None, region_code=None, region_name=None, city=None, zip_code=None, latitude=None, longitude=None, use_metric=True, time_zone='Europe/Amsterdam', ))): await client.send_json({ 'id': 1, 'type': 'config/core/detect', }) msg = await client.receive_json() assert msg['success'] is True assert msg['result'] == { 'unit_system': 'metric', 'time_zone': 'Europe/Amsterdam', }
async def test_create_default_config_detect_location(hass): """Test that detect location sets the correct config keys.""" with mock.patch('homeassistant.util.location.async_detect_location_info', return_value=mock_coro(location_util.LocationInfo( '0.0.0.0', 'US', 'United States', 'CA', 'California', 'San Diego', '92122', 'America/Los_Angeles', 32.8594, -117.2073, True))), \ mock.patch('homeassistant.util.location.async_get_elevation', return_value=mock_coro(101)), \ mock.patch('builtins.print') as mock_print: await config_util.async_ensure_config_exists(hass, CONFIG_DIR) config = config_util.load_yaml_config_file(YAML_PATH) assert DOMAIN in config ha_conf = config[DOMAIN] expected_values = { CONF_LATITUDE: 32.8594, CONF_LONGITUDE: -117.2073, CONF_ELEVATION: 101, CONF_UNIT_SYSTEM: CONF_UNIT_SYSTEM_METRIC, CONF_NAME: 'Home', CONF_TIME_ZONE: 'America/Los_Angeles', CONF_CUSTOMIZE: OrderedDict(), } assert expected_values == ha_conf assert mock_print.called
async def test_detect_config_fail(hass, client): """Test detect config.""" with patch( "homeassistant.util.location.async_detect_location_info", return_value=location.LocationInfo( ip=None, country_code=None, region_code=None, region_name=None, city=None, zip_code=None, latitude=None, longitude=None, use_metric=True, time_zone="Europe/Amsterdam", ), ): await client.send_json({"id": 1, "type": "config/core/detect"}) msg = await client.receive_json() assert msg["success"] is True assert msg["result"] == { "unit_system": "metric", "time_zone": "Europe/Amsterdam" }
def mock_detect_location_info(): """ Mock implementation of util.detect_location_info. """ return location_util.LocationInfo( ip='1.1.1.1', country_code='US', country_name='United States', region_code='CA', region_name='California', city='San Diego', zip_code='92122', time_zone='America/Los_Angeles', latitude='2.0', longitude='1.0', use_fahrenheit=True, )
with pytest.raises(MultipleInvalid): await config_util.async_process_ha_core_config(hass, { 'latitude': 39, 'longitude': -1, 'elevation': 500, 'name': 'Huis', CONF_TEMPERATURE_UNIT: 'C', 'time_zone': 'Europe/Madrid', 'packages': {'empty_package': None}, }) @asynctest.mock.patch( 'homeassistant.util.location.async_detect_location_info', autospec=True, return_value=mock_coro(location_util.LocationInfo( '0.0.0.0', 'US', 'United States', 'CA', 'California', 'San Diego', '92122', 'America/Los_Angeles', 32.8594, -117.2073, True))) @asynctest.mock.patch('homeassistant.util.location.async_get_elevation', autospec=True, return_value=mock_coro(101)) async def test_discovering_configuration(mock_detect, mock_elevation, hass): """Test auto discovery for missing core configs.""" hass.config.latitude = None hass.config.longitude = None hass.config.elevation = None hass.config.location_name = None hass.config.time_zone = None await config_util.async_process_ha_core_config(hass, {}) assert hass.config.latitude == 32.8594 assert hass.config.longitude == -117.2073
CONF_CODE: MOCK_CODE, } MOCK_DATA = {CONF_TOKEN: MOCK_CREDS, "devices": [MOCK_DEVICE]} MOCK_UDP_PORT = int(987) MOCK_TCP_PORT = int(997) MOCK_AUTO = {"Config Mode": "Auto Discover"} MOCK_MANUAL = {"Config Mode": "Manual Entry", CONF_IP_ADDRESS: MOCK_HOST} MOCK_LOCATION = location.LocationInfo( "0.0.0.0", "US", "United States", "CA", "California", "San Diego", "92122", "America/Los_Angeles", 32.8594, -117.2073, True, ) async def test_full_flow_implementation(hass): """Test registering an implementation and flow works.""" flow = ps4.PlayStation4FlowHandler() flow.hass = hass flow.location = MOCK_LOCATION manager = hass.config_entries
class TestConfig(unittest.TestCase): """Test the configutils.""" # pylint: disable=invalid-name def setUp(self): """Initialize a test Home Assistant instance.""" self.hass = get_test_home_assistant() # pylint: disable=invalid-name def tearDown(self): """Clean up.""" dt_util.DEFAULT_TIME_ZONE = ORIG_TIMEZONE if os.path.isfile(YAML_PATH): os.remove(YAML_PATH) if os.path.isfile(VERSION_PATH): os.remove(VERSION_PATH) self.hass.stop() def test_create_default_config(self): """Test creation of default config.""" config_util.create_default_config(CONFIG_DIR, False) self.assertTrue(os.path.isfile(YAML_PATH)) def test_find_config_file_yaml(self): """Test if it finds a YAML config file.""" create_file(YAML_PATH) self.assertEqual(YAML_PATH, config_util.find_config_file(CONFIG_DIR)) @mock.patch('builtins.print') def test_ensure_config_exists_creates_config(self, mock_print): """Test that calling ensure_config_exists. If not creates a new config file. """ config_util.ensure_config_exists(CONFIG_DIR, False) self.assertTrue(os.path.isfile(YAML_PATH)) self.assertTrue(mock_print.called) def test_ensure_config_exists_uses_existing_config(self): """Test that calling ensure_config_exists uses existing config.""" create_file(YAML_PATH) config_util.ensure_config_exists(CONFIG_DIR, False) with open(YAML_PATH) as f: content = f.read() # File created with create_file are empty self.assertEqual('', content) def test_load_yaml_config_converts_empty_files_to_dict(self): """Test that loading an empty file returns an empty dict.""" create_file(YAML_PATH) self.assertIsInstance(config_util.load_yaml_config_file(YAML_PATH), dict) def test_load_yaml_config_raises_error_if_not_dict(self): """Test error raised when YAML file is not a dict.""" with open(YAML_PATH, 'w') as f: f.write('5') with self.assertRaises(HomeAssistantError): config_util.load_yaml_config_file(YAML_PATH) def test_load_yaml_config_raises_error_if_malformed_yaml(self): """Test error raised if invalid YAML.""" with open(YAML_PATH, 'w') as f: f.write(':') with self.assertRaises(HomeAssistantError): config_util.load_yaml_config_file(YAML_PATH) def test_load_yaml_config_raises_error_if_unsafe_yaml(self): """Test error raised if unsafe YAML.""" with open(YAML_PATH, 'w') as f: f.write('hello: !!python/object/apply:os.system') with self.assertRaises(HomeAssistantError): config_util.load_yaml_config_file(YAML_PATH) def test_load_yaml_config_preserves_key_order(self): """Test removal of library.""" with open(YAML_PATH, 'w') as f: f.write('hello: 0\n') f.write('world: 1\n') self.assertEqual( [('hello', 0), ('world', 1)], list(config_util.load_yaml_config_file(YAML_PATH).items())) @mock.patch('homeassistant.util.location.detect_location_info', return_value=location_util.LocationInfo( '0.0.0.0', 'US', 'United States', 'CA', 'California', 'San Diego', '92122', 'America/Los_Angeles', 32.8594, -117.2073, True)) @mock.patch('homeassistant.util.location.elevation', return_value=101) @mock.patch('builtins.print') def test_create_default_config_detect_location(self, mock_detect, mock_elev, mock_print): """Test that detect location sets the correct config keys.""" config_util.ensure_config_exists(CONFIG_DIR) config = config_util.load_yaml_config_file(YAML_PATH) self.assertIn(DOMAIN, config) ha_conf = config[DOMAIN] expected_values = { CONF_LATITUDE: 32.8594, CONF_LONGITUDE: -117.2073, CONF_ELEVATION: 101, CONF_UNIT_SYSTEM: CONF_UNIT_SYSTEM_METRIC, CONF_NAME: 'Home', CONF_TIME_ZONE: 'America/Los_Angeles' } assert expected_values == ha_conf assert mock_print.called @mock.patch('builtins.print') def test_create_default_config_returns_none_if_write_error( self, mock_print): """Test the writing of a default configuration. Non existing folder returns None. """ self.assertIsNone( config_util.create_default_config( os.path.join(CONFIG_DIR, 'non_existing_dir/'), False)) self.assertTrue(mock_print.called) def test_core_config_schema(self): """Test core config schema.""" for value in ( { CONF_UNIT_SYSTEM: 'K' }, { 'time_zone': 'non-exist' }, { 'latitude': '91' }, { 'longitude': -181 }, { 'customize': 'bla' }, { 'customize': { 'invalid_entity_id': {} } }, { 'customize': { 'light.sensor': 100 } }, ): with pytest.raises(MultipleInvalid): config_util.CORE_CONFIG_SCHEMA(value) config_util.CORE_CONFIG_SCHEMA({ 'name': 'Test name', 'latitude': '-23.45', 'longitude': '123.45', CONF_UNIT_SYSTEM: CONF_UNIT_SYSTEM_METRIC, 'customize': { 'sensor.temperature': { 'hidden': True, }, }, }) def test_entity_customization(self): """Test entity customization through configuration.""" config = { CONF_LATITUDE: 50, CONF_LONGITUDE: 50, CONF_NAME: 'Test', CONF_CUSTOMIZE: { 'test.test': { 'hidden': True } } } run_coroutine_threadsafe( config_util.async_process_ha_core_config(self.hass, config), self.hass.loop).result() entity = Entity() entity.entity_id = 'test.test' entity.hass = self.hass entity.update_ha_state() self.hass.block_till_done() state = self.hass.states.get('test.test') assert state.attributes['hidden'] @mock.patch('homeassistant.config.shutil') @mock.patch('homeassistant.config.os') def test_remove_lib_on_upgrade(self, mock_os, mock_shutil): """Test removal of library on upgrade.""" ha_version = '0.7.0' mock_os.path.isdir = mock.Mock(return_value=True) mock_open = mock.mock_open() with mock.patch('homeassistant.config.open', mock_open, create=True): opened_file = mock_open.return_value opened_file.readline.return_value = ha_version self.hass.config.path = mock.Mock() config_util.process_ha_config_upgrade(self.hass) hass_path = self.hass.config.path.return_value self.assertEqual(mock_os.path.isdir.call_count, 1) self.assertEqual(mock_os.path.isdir.call_args, mock.call(hass_path)) self.assertEqual(mock_shutil.rmtree.call_count, 1) self.assertEqual(mock_shutil.rmtree.call_args, mock.call(hass_path)) @mock.patch('homeassistant.config.shutil') @mock.patch('homeassistant.config.os') def test_not_remove_lib_if_not_upgrade(self, mock_os, mock_shutil): """Test removal of library with no upgrade.""" ha_version = __version__ mock_os.path.isdir = mock.Mock(return_value=True) mock_open = mock.mock_open() with mock.patch('homeassistant.config.open', mock_open, create=True): opened_file = mock_open.return_value opened_file.readline.return_value = ha_version self.hass.config.path = mock.Mock() config_util.process_ha_config_upgrade(self.hass) assert mock_os.path.isdir.call_count == 0 assert mock_shutil.rmtree.call_count == 0 def test_loading_configuration(self): """Test loading core config onto hass object.""" self.hass.config = mock.Mock() run_coroutine_threadsafe( config_util.async_process_ha_core_config( self.hass, { 'latitude': 60, 'longitude': 50, 'elevation': 25, 'name': 'Huis', CONF_UNIT_SYSTEM: CONF_UNIT_SYSTEM_IMPERIAL, 'time_zone': 'America/New_York', }), self.hass.loop).result() assert self.hass.config.latitude == 60 assert self.hass.config.longitude == 50 assert self.hass.config.elevation == 25 assert self.hass.config.location_name == 'Huis' assert self.hass.config.units.name == CONF_UNIT_SYSTEM_IMPERIAL assert self.hass.config.time_zone.zone == 'America/New_York' def test_loading_configuration_temperature_unit(self): """Test backward compatibility when loading core config.""" self.hass.config = mock.Mock() run_coroutine_threadsafe( config_util.async_process_ha_core_config( self.hass, { 'latitude': 60, 'longitude': 50, 'elevation': 25, 'name': 'Huis', CONF_TEMPERATURE_UNIT: 'C', 'time_zone': 'America/New_York', }), self.hass.loop).result() assert self.hass.config.latitude == 60 assert self.hass.config.longitude == 50 assert self.hass.config.elevation == 25 assert self.hass.config.location_name == 'Huis' assert self.hass.config.units.name == CONF_UNIT_SYSTEM_METRIC assert self.hass.config.time_zone.zone == 'America/New_York' @mock.patch('homeassistant.util.location.detect_location_info', autospec=True, return_value=location_util.LocationInfo( '0.0.0.0', 'US', 'United States', 'CA', 'California', 'San Diego', '92122', 'America/Los_Angeles', 32.8594, -117.2073, True)) @mock.patch('homeassistant.util.location.elevation', autospec=True, return_value=101) def test_discovering_configuration(self, mock_detect, mock_elevation): """Test auto discovery for missing core configs.""" self.hass.config.latitude = None self.hass.config.longitude = None self.hass.config.elevation = None self.hass.config.location_name = None self.hass.config.time_zone = None run_coroutine_threadsafe( config_util.async_process_ha_core_config(self.hass, {}), self.hass.loop).result() assert self.hass.config.latitude == 32.8594 assert self.hass.config.longitude == -117.2073 assert self.hass.config.elevation == 101 assert self.hass.config.location_name == 'San Diego' assert self.hass.config.units.name == CONF_UNIT_SYSTEM_METRIC assert self.hass.config.units.is_metric assert self.hass.config.time_zone.zone == 'America/Los_Angeles' @mock.patch('homeassistant.util.location.detect_location_info', autospec=True, return_value=None) @mock.patch('homeassistant.util.location.elevation', return_value=0) def test_discovering_configuration_auto_detect_fails( self, mock_detect, mock_elevation): """Test config remains unchanged if discovery fails.""" self.hass.config = Config() run_coroutine_threadsafe( config_util.async_process_ha_core_config(self.hass, {}), self.hass.loop).result() blankConfig = Config() assert self.hass.config.latitude == blankConfig.latitude assert self.hass.config.longitude == blankConfig.longitude assert self.hass.config.elevation == blankConfig.elevation assert self.hass.config.location_name == blankConfig.location_name assert self.hass.config.units == blankConfig.units assert self.hass.config.time_zone == blankConfig.time_zone
class TestConfig(unittest.TestCase): """Test the configutils.""" # pylint: disable=invalid-name def setUp(self): """Initialize a test Home Assistant instance.""" self.hass = get_test_home_assistant() # pylint: disable=invalid-name def tearDown(self): """Clean up.""" dt_util.DEFAULT_TIME_ZONE = ORIG_TIMEZONE if os.path.isfile(YAML_PATH): os.remove(YAML_PATH) if os.path.isfile(SECRET_PATH): os.remove(SECRET_PATH) if os.path.isfile(VERSION_PATH): os.remove(VERSION_PATH) if os.path.isfile(GROUP_PATH): os.remove(GROUP_PATH) if os.path.isfile(AUTOMATIONS_PATH): os.remove(AUTOMATIONS_PATH) if os.path.isfile(SCRIPTS_PATH): os.remove(SCRIPTS_PATH) if os.path.isfile(CUSTOMIZE_PATH): os.remove(CUSTOMIZE_PATH) self.hass.stop() # pylint: disable=no-self-use def test_create_default_config(self): """Test creation of default config.""" config_util.create_default_config(CONFIG_DIR, False) assert os.path.isfile(YAML_PATH) assert os.path.isfile(SECRET_PATH) assert os.path.isfile(VERSION_PATH) assert os.path.isfile(GROUP_PATH) assert os.path.isfile(AUTOMATIONS_PATH) assert os.path.isfile(CUSTOMIZE_PATH) def test_find_config_file_yaml(self): """Test if it finds a YAML config file.""" create_file(YAML_PATH) assert YAML_PATH == config_util.find_config_file(CONFIG_DIR) @mock.patch('builtins.print') def test_ensure_config_exists_creates_config(self, mock_print): """Test that calling ensure_config_exists. If not creates a new config file. """ config_util.ensure_config_exists(CONFIG_DIR, False) assert os.path.isfile(YAML_PATH) assert mock_print.called def test_ensure_config_exists_uses_existing_config(self): """Test that calling ensure_config_exists uses existing config.""" create_file(YAML_PATH) config_util.ensure_config_exists(CONFIG_DIR, False) with open(YAML_PATH) as f: content = f.read() # File created with create_file are empty assert '' == content def test_load_yaml_config_converts_empty_files_to_dict(self): """Test that loading an empty file returns an empty dict.""" create_file(YAML_PATH) assert isinstance(config_util.load_yaml_config_file(YAML_PATH), dict) def test_load_yaml_config_raises_error_if_not_dict(self): """Test error raised when YAML file is not a dict.""" with open(YAML_PATH, 'w') as f: f.write('5') with pytest.raises(HomeAssistantError): config_util.load_yaml_config_file(YAML_PATH) def test_load_yaml_config_raises_error_if_malformed_yaml(self): """Test error raised if invalid YAML.""" with open(YAML_PATH, 'w') as f: f.write(':') with pytest.raises(HomeAssistantError): config_util.load_yaml_config_file(YAML_PATH) def test_load_yaml_config_raises_error_if_unsafe_yaml(self): """Test error raised if unsafe YAML.""" with open(YAML_PATH, 'w') as f: f.write('hello: !!python/object/apply:os.system') with pytest.raises(HomeAssistantError): config_util.load_yaml_config_file(YAML_PATH) def test_load_yaml_config_preserves_key_order(self): """Test removal of library.""" with open(YAML_PATH, 'w') as f: f.write('hello: 2\n') f.write('world: 1\n') assert [('hello', 2), ('world', 1)] == \ list(config_util.load_yaml_config_file(YAML_PATH).items()) @mock.patch('homeassistant.util.location.detect_location_info', return_value=location_util.LocationInfo( '0.0.0.0', 'US', 'United States', 'CA', 'California', 'San Diego', '92122', 'America/Los_Angeles', 32.8594, -117.2073, True)) @mock.patch('homeassistant.util.location.elevation', return_value=101) @mock.patch('builtins.print') def test_create_default_config_detect_location(self, mock_detect, mock_elev, mock_print): """Test that detect location sets the correct config keys.""" config_util.ensure_config_exists(CONFIG_DIR) config = config_util.load_yaml_config_file(YAML_PATH) assert DOMAIN in config ha_conf = config[DOMAIN] expected_values = { CONF_LATITUDE: 32.8594, CONF_LONGITUDE: -117.2073, CONF_ELEVATION: 101, CONF_UNIT_SYSTEM: CONF_UNIT_SYSTEM_METRIC, CONF_NAME: 'Home', CONF_TIME_ZONE: 'America/Los_Angeles', CONF_CUSTOMIZE: OrderedDict(), } assert expected_values == ha_conf assert mock_print.called @mock.patch('builtins.print') def test_create_default_config_returns_none_if_write_error( self, mock_print): """Test the writing of a default configuration. Non existing folder returns None. """ assert config_util.create_default_config( os.path.join(CONFIG_DIR, 'non_existing_dir/'), False) is None assert mock_print.called # pylint: disable=no-self-use def test_core_config_schema(self): """Test core config schema.""" for value in ( { CONF_UNIT_SYSTEM: 'K' }, { 'time_zone': 'non-exist' }, { 'latitude': '91' }, { 'longitude': -181 }, { 'customize': 'bla' }, { 'customize': { 'light.sensor': 100 } }, { 'customize': { 'entity_id': [] } }, ): with pytest.raises(MultipleInvalid): config_util.CORE_CONFIG_SCHEMA(value) config_util.CORE_CONFIG_SCHEMA({ 'name': 'Test name', 'latitude': '-23.45', 'longitude': '123.45', CONF_UNIT_SYSTEM: CONF_UNIT_SYSTEM_METRIC, 'customize': { 'sensor.temperature': { 'hidden': True, }, }, }) def test_customize_dict_schema(self): """Test basic customize config validation.""" values = ( { ATTR_FRIENDLY_NAME: None }, { ATTR_HIDDEN: '2' }, { ATTR_ASSUMED_STATE: '2' }, ) for val in values: print(val) with pytest.raises(MultipleInvalid): config_util.CUSTOMIZE_DICT_SCHEMA(val) assert config_util.CUSTOMIZE_DICT_SCHEMA({ ATTR_FRIENDLY_NAME: 2, ATTR_HIDDEN: '1', ATTR_ASSUMED_STATE: '0', }) == { ATTR_FRIENDLY_NAME: '2', ATTR_HIDDEN: True, ATTR_ASSUMED_STATE: False } def test_customize_glob_is_ordered(self): """Test that customize_glob preserves order.""" conf = config_util.CORE_CONFIG_SCHEMA( {'customize_glob': OrderedDict()}) assert isinstance(conf['customize_glob'], OrderedDict) def _compute_state(self, config): run_coroutine_threadsafe( config_util.async_process_ha_core_config(self.hass, config), self.hass.loop).result() entity = Entity() entity.entity_id = 'test.test' entity.hass = self.hass entity.schedule_update_ha_state() self.hass.block_till_done() return self.hass.states.get('test.test') def test_entity_customization(self): """Test entity customization through configuration.""" config = { CONF_LATITUDE: 50, CONF_LONGITUDE: 50, CONF_NAME: 'Test', CONF_CUSTOMIZE: { 'test.test': { 'hidden': True } } } state = self._compute_state(config) assert state.attributes['hidden'] @mock.patch('homeassistant.config.shutil') @mock.patch('homeassistant.config.os') def test_remove_lib_on_upgrade(self, mock_os, mock_shutil): """Test removal of library on upgrade from before 0.50.""" ha_version = '0.49.0' mock_os.path.isdir = mock.Mock(return_value=True) mock_open = mock.mock_open() with mock.patch('homeassistant.config.open', mock_open, create=True): opened_file = mock_open.return_value # pylint: disable=no-member opened_file.readline.return_value = ha_version self.hass.config.path = mock.Mock() config_util.process_ha_config_upgrade(self.hass) hass_path = self.hass.config.path.return_value assert mock_os.path.isdir.call_count == 1 assert mock_os.path.isdir.call_args == mock.call(hass_path) assert mock_shutil.rmtree.call_count == 1 assert mock_shutil.rmtree.call_args == mock.call(hass_path) def test_process_config_upgrade(self): """Test update of version on upgrade.""" ha_version = '0.8.0' mock_open = mock.mock_open() with mock.patch('homeassistant.config.open', mock_open, create=True): opened_file = mock_open.return_value # pylint: disable=no-member opened_file.readline.return_value = ha_version config_util.process_ha_config_upgrade(self.hass) assert opened_file.write.call_count == 1 assert opened_file.write.call_args == mock.call(__version__) def test_config_upgrade_same_version(self): """Test no update of version on no upgrade.""" ha_version = __version__ mock_open = mock.mock_open() with mock.patch('homeassistant.config.open', mock_open, create=True): opened_file = mock_open.return_value # pylint: disable=no-member opened_file.readline.return_value = ha_version config_util.process_ha_config_upgrade(self.hass) assert opened_file.write.call_count == 0 def test_config_upgrade_no_file(self): """Test update of version on upgrade, with no version file.""" mock_open = mock.mock_open() mock_open.side_effect = [FileNotFoundError(), mock.DEFAULT] with mock.patch('homeassistant.config.open', mock_open, create=True): opened_file = mock_open.return_value # pylint: disable=no-member config_util.process_ha_config_upgrade(self.hass) assert opened_file.write.call_count == 1 assert opened_file.write.call_args == mock.call(__version__) @mock.patch('homeassistant.config.shutil') @mock.patch('homeassistant.config.os') def test_migrate_file_on_upgrade(self, mock_os, mock_shutil): """Test migrate of config files on upgrade.""" ha_version = '0.7.0' mock_os.path.isdir = mock.Mock(return_value=True) mock_open = mock.mock_open() def _mock_isfile(filename): return True with mock.patch('homeassistant.config.open', mock_open, create=True), \ mock.patch( 'homeassistant.config.os.path.isfile', _mock_isfile): opened_file = mock_open.return_value # pylint: disable=no-member opened_file.readline.return_value = ha_version self.hass.config.path = mock.Mock() config_util.process_ha_config_upgrade(self.hass) assert mock_os.rename.call_count == 1 @mock.patch('homeassistant.config.shutil') @mock.patch('homeassistant.config.os') def test_migrate_no_file_on_upgrade(self, mock_os, mock_shutil): """Test not migrating config files on upgrade.""" ha_version = '0.7.0' mock_os.path.isdir = mock.Mock(return_value=True) mock_open = mock.mock_open() def _mock_isfile(filename): return False with mock.patch('homeassistant.config.open', mock_open, create=True), \ mock.patch( 'homeassistant.config.os.path.isfile', _mock_isfile): opened_file = mock_open.return_value # pylint: disable=no-member opened_file.readline.return_value = ha_version self.hass.config.path = mock.Mock() config_util.process_ha_config_upgrade(self.hass) assert mock_os.rename.call_count == 0 def test_loading_configuration(self): """Test loading core config onto hass object.""" self.hass.config = mock.Mock() run_coroutine_threadsafe( config_util.async_process_ha_core_config( self.hass, { 'latitude': 60, 'longitude': 50, 'elevation': 25, 'name': 'Huis', CONF_UNIT_SYSTEM: CONF_UNIT_SYSTEM_IMPERIAL, 'time_zone': 'America/New_York', 'whitelist_external_dirs': '/tmp', }), self.hass.loop).result() assert self.hass.config.latitude == 60 assert self.hass.config.longitude == 50 assert self.hass.config.elevation == 25 assert self.hass.config.location_name == 'Huis' assert self.hass.config.units.name == CONF_UNIT_SYSTEM_IMPERIAL assert self.hass.config.time_zone.zone == 'America/New_York' assert len(self.hass.config.whitelist_external_dirs) == 2 assert '/tmp' in self.hass.config.whitelist_external_dirs def test_loading_configuration_temperature_unit(self): """Test backward compatibility when loading core config.""" self.hass.config = mock.Mock() run_coroutine_threadsafe( config_util.async_process_ha_core_config( self.hass, { 'latitude': 60, 'longitude': 50, 'elevation': 25, 'name': 'Huis', CONF_TEMPERATURE_UNIT: 'C', 'time_zone': 'America/New_York', }), self.hass.loop).result() assert self.hass.config.latitude == 60 assert self.hass.config.longitude == 50 assert self.hass.config.elevation == 25 assert self.hass.config.location_name == 'Huis' assert self.hass.config.units.name == CONF_UNIT_SYSTEM_METRIC assert self.hass.config.time_zone.zone == 'America/New_York' def test_loading_configuration_from_packages(self): """Test loading packages config onto hass object config.""" self.hass.config = mock.Mock() run_coroutine_threadsafe( config_util.async_process_ha_core_config( self.hass, { 'latitude': 39, 'longitude': -1, 'elevation': 500, 'name': 'Huis', CONF_TEMPERATURE_UNIT: 'C', 'time_zone': 'Europe/Madrid', 'packages': { 'package_1': { 'wake_on_lan': None }, 'package_2': { 'light': { 'platform': 'hue' }, 'media_extractor': None, 'sun': None } }, }), self.hass.loop).result() # Empty packages not allowed with pytest.raises(MultipleInvalid): run_coroutine_threadsafe( config_util.async_process_ha_core_config( self.hass, { 'latitude': 39, 'longitude': -1, 'elevation': 500, 'name': 'Huis', CONF_TEMPERATURE_UNIT: 'C', 'time_zone': 'Europe/Madrid', 'packages': { 'empty_package': None }, }), self.hass.loop).result() @mock.patch('homeassistant.util.location.detect_location_info', autospec=True, return_value=location_util.LocationInfo( '0.0.0.0', 'US', 'United States', 'CA', 'California', 'San Diego', '92122', 'America/Los_Angeles', 32.8594, -117.2073, True)) @mock.patch('homeassistant.util.location.elevation', autospec=True, return_value=101) def test_discovering_configuration(self, mock_detect, mock_elevation): """Test auto discovery for missing core configs.""" self.hass.config.latitude = None self.hass.config.longitude = None self.hass.config.elevation = None self.hass.config.location_name = None self.hass.config.time_zone = None run_coroutine_threadsafe( config_util.async_process_ha_core_config(self.hass, {}), self.hass.loop).result() assert self.hass.config.latitude == 32.8594 assert self.hass.config.longitude == -117.2073 assert self.hass.config.elevation == 101 assert self.hass.config.location_name == 'San Diego' assert self.hass.config.units.name == CONF_UNIT_SYSTEM_METRIC assert self.hass.config.units.is_metric assert self.hass.config.time_zone.zone == 'America/Los_Angeles' @mock.patch('homeassistant.util.location.detect_location_info', autospec=True, return_value=None) @mock.patch('homeassistant.util.location.elevation', return_value=0) def test_discovering_configuration_auto_detect_fails( self, mock_detect, mock_elevation): """Test config remains unchanged if discovery fails.""" self.hass.config = Config() self.hass.config.config_dir = "/test/config" run_coroutine_threadsafe( config_util.async_process_ha_core_config(self.hass, {}), self.hass.loop).result() blankConfig = Config() assert self.hass.config.latitude == blankConfig.latitude assert self.hass.config.longitude == blankConfig.longitude assert self.hass.config.elevation == blankConfig.elevation assert self.hass.config.location_name == blankConfig.location_name assert self.hass.config.units == blankConfig.units assert self.hass.config.time_zone == blankConfig.time_zone assert len(self.hass.config.whitelist_external_dirs) == 1 assert "/test/config/www" in self.hass.config.whitelist_external_dirs @mock.patch('homeassistant.scripts.check_config.check_ha_config_file') def test_check_ha_config_file_correct(self, mock_check): """Check that restart propagates to stop.""" mock_check.return_value = check_config.HomeAssistantConfig() assert run_coroutine_threadsafe( config_util.async_check_ha_config_file(self.hass), self.hass.loop).result() is None @mock.patch('homeassistant.scripts.check_config.check_ha_config_file') def test_check_ha_config_file_wrong(self, mock_check): """Check that restart with a bad config doesn't propagate to stop.""" mock_check.return_value = check_config.HomeAssistantConfig() mock_check.return_value.add_error("bad") assert run_coroutine_threadsafe( config_util.async_check_ha_config_file(self.hass), self.hass.loop).result() == 'bad'
'elevation': 500, 'name': 'Huis', CONF_TEMPERATURE_UNIT: 'C', 'time_zone': 'Europe/Madrid', 'packages': { 'empty_package': None }, }) @asynctest.mock.patch( 'homeassistant.util.location.async_detect_location_info', autospec=True, return_value=mock_coro( location_util.LocationInfo('0.0.0.0', 'US', 'United States', 'CA', 'California', 'San Diego', '92122', 'America/Los_Angeles', 32.8594, -117.2073, True))) @asynctest.mock.patch('homeassistant.util.location.async_get_elevation', autospec=True, return_value=mock_coro(101)) async def test_discovering_configuration(mock_detect, mock_elevation, hass): """Test auto discovery for missing core configs.""" hass.config.latitude = None hass.config.longitude = None hass.config.elevation = None hass.config.location_name = None hass.config.time_zone = None await config_util.async_process_ha_core_config(hass, {}) assert hass.config.latitude == 32.8594
class TestConfig(unittest.TestCase): """Test the configutils.""" def tearDown(self): # pylint: disable=invalid-name """Clean up.""" dt_util.DEFAULT_TIME_ZONE = ORIG_TIMEZONE if os.path.isfile(YAML_PATH): os.remove(YAML_PATH) if os.path.isfile(VERSION_PATH): os.remove(VERSION_PATH) if hasattr(self, 'hass'): self.hass.stop() def test_create_default_config(self): """Test creation of default config.""" config_util.create_default_config(CONFIG_DIR, False) self.assertTrue(os.path.isfile(YAML_PATH)) def test_find_config_file_yaml(self): """Test if it finds a YAML config file.""" create_file(YAML_PATH) self.assertEqual(YAML_PATH, config_util.find_config_file(CONFIG_DIR)) @mock.patch('builtins.print') def test_ensure_config_exists_creates_config(self, mock_print): """Test that calling ensure_config_exists. If not creates a new config file. """ config_util.ensure_config_exists(CONFIG_DIR, False) self.assertTrue(os.path.isfile(YAML_PATH)) self.assertTrue(mock_print.called) def test_ensure_config_exists_uses_existing_config(self): """Test that calling ensure_config_exists uses existing config.""" create_file(YAML_PATH) config_util.ensure_config_exists(CONFIG_DIR, False) with open(YAML_PATH) as f: content = f.read() # File created with create_file are empty self.assertEqual('', content) def test_load_yaml_config_converts_empty_files_to_dict(self): """Test that loading an empty file returns an empty dict.""" create_file(YAML_PATH) self.assertIsInstance( config_util.load_yaml_config_file(YAML_PATH), dict) def test_load_yaml_config_raises_error_if_not_dict(self): """Test error raised when YAML file is not a dict.""" with open(YAML_PATH, 'w') as f: f.write('5') with self.assertRaises(HomeAssistantError): config_util.load_yaml_config_file(YAML_PATH) def test_load_yaml_config_raises_error_if_malformed_yaml(self): """Test error raised if invalid YAML.""" with open(YAML_PATH, 'w') as f: f.write(':') with self.assertRaises(HomeAssistantError): config_util.load_yaml_config_file(YAML_PATH) def test_load_yaml_config_raises_error_if_unsafe_yaml(self): """Test error raised if unsafe YAML.""" with open(YAML_PATH, 'w') as f: f.write('hello: !!python/object/apply:os.system') with self.assertRaises(HomeAssistantError): config_util.load_yaml_config_file(YAML_PATH) def test_load_yaml_config_preserves_key_order(self): """Test removal of library.""" with open(YAML_PATH, 'w') as f: f.write('hello: 0\n') f.write('world: 1\n') self.assertEqual( [('hello', 0), ('world', 1)], list(config_util.load_yaml_config_file(YAML_PATH).items())) @mock.patch('homeassistant.util.location.detect_location_info', return_value=location_util.LocationInfo( '0.0.0.0', 'US', 'United States', 'CA', 'California', 'San Diego', '92122', 'America/Los_Angeles', 32.8594, -117.2073, True)) @mock.patch('homeassistant.util.location.elevation', return_value=101) @mock.patch('builtins.print') def test_create_default_config_detect_location(self, mock_detect, mock_elev, mock_print): """Test that detect location sets the correct config keys.""" config_util.ensure_config_exists(CONFIG_DIR) config = config_util.load_yaml_config_file(YAML_PATH) self.assertIn(DOMAIN, config) ha_conf = config[DOMAIN] expected_values = { CONF_LATITUDE: 32.8594, CONF_LONGITUDE: -117.2073, CONF_ELEVATION: 101, CONF_TEMPERATURE_UNIT: 'F', CONF_NAME: 'Home', CONF_TIME_ZONE: 'America/Los_Angeles' } assert expected_values == ha_conf assert mock_print.called @mock.patch('builtins.print') def test_create_default_config_returns_none_if_write_error(self, mock_print): """Test the writing of a default configuration. Non existing folder returns None. """ self.assertIsNone( config_util.create_default_config( os.path.join(CONFIG_DIR, 'non_existing_dir/'), False)) self.assertTrue(mock_print.called) def test_core_config_schema(self): for value in ( {'temperature_unit': 'K'}, {'time_zone': 'non-exist'}, {'latitude': '91'}, {'longitude': -181}, {'customize': 'bla'}, {'customize': {'invalid_entity_id': {}}}, {'customize': {'light.sensor': 100}}, ): with pytest.raises(MultipleInvalid): config_util.CORE_CONFIG_SCHEMA(value) config_util.CORE_CONFIG_SCHEMA({ 'name': 'Test name', 'latitude': '-23.45', 'longitude': '123.45', 'temperature_unit': 'c', 'customize': { 'sensor.temperature': { 'hidden': True, }, }, }) def test_entity_customization(self): """Test entity customization through configuration.""" self.hass = get_test_home_assistant() config = {CONF_LATITUDE: 50, CONF_LONGITUDE: 50, CONF_NAME: 'Test', CONF_CUSTOMIZE: {'test.test': {'hidden': True}}} config_util.process_ha_core_config(self.hass, config) entity = Entity() entity.entity_id = 'test.test' entity.hass = self.hass entity.update_ha_state() state = self.hass.states.get('test.test') assert state.attributes['hidden'] def test_remove_lib_on_upgrade(self): """Test removal of library on upgrade.""" with tempfile.TemporaryDirectory() as config_dir: version_path = os.path.join(config_dir, '.HA_VERSION') lib_dir = os.path.join(config_dir, 'deps') check_file = os.path.join(lib_dir, 'check') with open(version_path, 'wt') as outp: outp.write('0.7.0') os.mkdir(lib_dir) with open(check_file, 'w'): pass self.hass = get_test_home_assistant() self.hass.config.config_dir = config_dir assert os.path.isfile(check_file) config_util.process_ha_config_upgrade(self.hass) assert not os.path.isfile(check_file) def test_not_remove_lib_if_not_upgrade(self): """Test removal of library with no upgrade.""" with tempfile.TemporaryDirectory() as config_dir: version_path = os.path.join(config_dir, '.HA_VERSION') lib_dir = os.path.join(config_dir, 'deps') check_file = os.path.join(lib_dir, 'check') with open(version_path, 'wt') as outp: outp.write(__version__) os.mkdir(lib_dir) with open(check_file, 'w'): pass self.hass = get_test_home_assistant() self.hass.config.config_dir = config_dir config_util.process_ha_config_upgrade(self.hass) assert os.path.isfile(check_file) def test_loading_configuration(self): """Test loading core config onto hass object.""" config = Config() hass = mock.Mock(config=config) config_util.process_ha_core_config(hass, { 'latitude': 60, 'longitude': 50, 'elevation': 25, 'name': 'Huis', 'temperature_unit': 'F', 'time_zone': 'America/New_York', }) assert config.latitude == 60 assert config.longitude == 50 assert config.elevation == 25 assert config.location_name == 'Huis' assert config.temperature_unit == TEMP_FAHRENHEIT assert config.time_zone.zone == 'America/New_York' @mock.patch('homeassistant.util.location.detect_location_info', return_value=location_util.LocationInfo( '0.0.0.0', 'US', 'United States', 'CA', 'California', 'San Diego', '92122', 'America/Los_Angeles', 32.8594, -117.2073, True)) @mock.patch('homeassistant.util.location.elevation', return_value=101) def test_discovering_configuration(self, mock_detect, mock_elevation): """Test auto discovery for missing core configs.""" config = Config() hass = mock.Mock(config=config) config_util.process_ha_core_config(hass, {}) assert config.latitude == 32.8594 assert config.longitude == -117.2073 assert config.elevation == 101 assert config.location_name == 'San Diego' assert config.temperature_unit == TEMP_FAHRENHEIT assert config.time_zone.zone == 'America/Los_Angeles' @mock.patch('homeassistant.util.location.detect_location_info', return_value=None) @mock.patch('homeassistant.util.location.elevation', return_value=0) def test_discovering_configuration_auto_detect_fails(self, mock_detect, mock_elevation): """Test config remains unchanged if discovery fails.""" config = Config() hass = mock.Mock(config=config) config_util.process_ha_core_config(hass, {}) blankConfig = Config() assert config.latitude == blankConfig.latitude assert config.longitude == blankConfig.longitude assert config.elevation == blankConfig.elevation assert config.location_name == blankConfig.location_name assert config.temperature_unit == blankConfig.temperature_unit assert config.time_zone == blankConfig.time_zone
~~~~~~~~~~~~~~ Tests initialization. """ import betamax from homeassistant import util from homeassistant.util import location with betamax.Betamax.configure() as config: config.cassette_library_dir = 'tests/cassettes' # Automatically called during different setups. Too often forgotten # so mocked by default. location.detect_location_info = lambda: location.LocationInfo( ip='1.1.1.1', country_code='US', country_name='United States', region_code='CA', region_name='California', city='San Diego', zip_code='92122', time_zone='America/Los_Angeles', latitude='2.0', longitude='1.0', use_fahrenheit=True, ) location.elevation = lambda latitude, longitude: 0 util.get_local_ip = lambda: '127.0.0.1'