async def test_ssdp_byebye( hass: HomeAssistant, ssdp_scanner_mock: Mock, connected_source_mock: DmsDeviceSource, ) -> None: """Test device is disconnected when byebye is received.""" # First byebye will cause a disconnect ssdp_callback = ssdp_scanner_mock.async_register_callback.call_args.args[0] await ssdp_callback( ssdp.SsdpServiceInfo( ssdp_usn=MOCK_DEVICE_USN, ssdp_udn=MOCK_DEVICE_UDN, ssdp_headers={"NTS": "ssdp:byebye"}, ssdp_st=MOCK_DEVICE_TYPE, upnp={}, ), ssdp.SsdpChange.BYEBYE, ) # Device should be gone assert not connected_source_mock.available # Second byebye will do nothing await ssdp_callback( ssdp.SsdpServiceInfo( ssdp_usn=MOCK_DEVICE_USN, ssdp_udn=MOCK_DEVICE_UDN, ssdp_headers={"NTS": "ssdp:byebye"}, ssdp_st=MOCK_DEVICE_TYPE, upnp={}, ), ssdp.SsdpChange.BYEBYE, )
async def test_multiple_ssdp_alive( hass: HomeAssistant, upnp_factory_mock: Mock, ssdp_scanner_mock: Mock, disconnected_source_mock: None, ) -> None: """Test multiple SSDP alive notifications is ok, only connects to device once.""" upnp_factory_mock.async_create_device.reset_mock() # Contacting the device takes long enough that 2 simultaneous attempts could be made async def create_device_delayed(_location): """Delay before continuing with async_create_device. This gives a chance for parallel calls to `device_connect` to occur. """ await asyncio.sleep(0.1) return DEFAULT upnp_factory_mock.async_create_device.side_effect = create_device_delayed # Send two SSDP notifications with the new device URL ssdp_callback = ssdp_scanner_mock.async_register_callback.call_args.args[0] await ssdp_callback( ssdp.SsdpServiceInfo( ssdp_usn=MOCK_DEVICE_USN, ssdp_location=NEW_DEVICE_LOCATION, ssdp_st=MOCK_DEVICE_TYPE, upnp={}, ), ssdp.SsdpChange.ALIVE, ) await ssdp_callback( ssdp.SsdpServiceInfo( ssdp_usn=MOCK_DEVICE_USN, ssdp_location=NEW_DEVICE_LOCATION, ssdp_st=MOCK_DEVICE_TYPE, upnp={}, ), ssdp.SsdpChange.ALIVE, ) await hass.async_block_till_done() # Check device is contacted exactly once upnp_factory_mock.async_create_device.assert_awaited_once_with( NEW_DEVICE_LOCATION) # Device should be available await assert_source_available(hass)
async def test_duplicate_ssdp_ignored(hass: HomeAssistant) -> None: """Test that duplicate ssdp form is note shown.""" MockConfigEntry( domain=DOMAIN, data={ "host": "192.168.1.123" }, source=config_entries.SOURCE_IMPORT, unique_id="83747482", ).add_to_hass(hass) result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_SSDP}, data=ssdp.SsdpServiceInfo( ssdp_usn="mock_usn", ssdp_st="mock_st", upnp={ "presentationURL": "http://192.168.1.123:80/discovery/device.xml", "port": 80, "UDN": "uuid:83747482", }, ), ) assert result["type"] == "abort" assert result["reason"] == "already_configured"
async def test_ssdp_discovery_existing_device_update(hass, mock_ssdp_yamaha, mock_get_source_ip): """Test when the SSDP discovered device is a musiccast device, but it already exists with another IP.""" mock_entry = MockConfigEntry( domain=DOMAIN, unique_id="1234567890", data={ CONF_HOST: "192.168.188.18", "model": "MC20", "serial": "1234567890" }, ) mock_entry.add_to_hass(hass) result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_SSDP}, data=ssdp.SsdpServiceInfo( ssdp_usn="mock_usn", ssdp_st="mock_st", ssdp_location="http://127.0.0.1/desc.xml", upnp={ ssdp.ATTR_UPNP_MODEL_NAME: "MC20", ssdp.ATTR_UPNP_SERIAL: "1234567890", }, ), ) assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT assert result["reason"] == "already_configured" assert mock_entry.data[CONF_HOST] == "127.0.0.1" assert mock_entry.data["upnp_description"] == "http://127.0.0.1/desc.xml"
async def test_ssdp_discovery_successful_add_device(hass, mock_ssdp_yamaha, mock_get_source_ip): """Test when the SSDP discovered device is a musiccast device and the user confirms it.""" result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_SSDP}, data=ssdp.SsdpServiceInfo( ssdp_usn="mock_usn", ssdp_st="mock_st", ssdp_location="http://127.0.0.1/desc.xml", upnp={ ssdp.ATTR_UPNP_MODEL_NAME: "MC20", ssdp.ATTR_UPNP_SERIAL: "1234567890", }, ), ) assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["errors"] is None assert result["step_id"] == "confirm" result2 = await hass.config_entries.flow.async_configure( result["flow_id"], {}, ) assert result2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert isinstance(result2["result"], ConfigEntry) assert result2["data"] == { "host": "127.0.0.1", "serial": "1234567890", "upnp_description": "http://127.0.0.1/desc.xml", }
async def test_catch_request_error_unavailable( hass: HomeAssistant, ssdp_scanner_mock: Mock) -> None: """Test the device is checked for availability before trying requests.""" # DmsDevice notifies of disconnect via SSDP ssdp_callback = ssdp_scanner_mock.async_register_callback.call_args.args[0] await ssdp_callback( ssdp.SsdpServiceInfo( ssdp_usn=MOCK_DEVICE_USN, ssdp_udn=MOCK_DEVICE_UDN, ssdp_headers={"NTS": "ssdp:byebye"}, ssdp_st=MOCK_DEVICE_TYPE, upnp={}, ), ssdp.SsdpChange.BYEBYE, ) # All attempts to use the device should give an error with pytest.raises(Unresolvable, match="DMS is not connected"): # Resolve object await async_resolve_media(hass, ":id") with pytest.raises(Unresolvable, match="DMS is not connected"): # Resolve path await async_resolve_media(hass, "/path") with pytest.raises(Unresolvable, match="DMS is not connected"): # Resolve search await async_resolve_media(hass, "?query") with pytest.raises(BrowseError, match="DMS is not connected"): # Browse object await async_browse_media(hass, ":id") with pytest.raises(BrowseError, match="DMS is not connected"): # Browse path await async_browse_media(hass, "/path") with pytest.raises(BrowseError, match="DMS is not connected"): # Browse search await async_browse_media(hass, "?query")
async def test_ssdp(hass, aioclient_mock): """Test SSDP discovery initiates config properly.""" mock_connection(aioclient_mock) url = "http://192.168.1.2/" result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_SSDP}, data=ssdp.SsdpServiceInfo( ssdp_usn="mock_usn", ssdp_st="mock_st", ssdp_location="http://192.168.1.2:5200/Printer.xml", upnp={ ssdp.ATTR_UPNP_DEVICE_TYPE: "urn:schemas-upnp-org:device:Printer:1", ssdp.ATTR_UPNP_MANUFACTURER: "Samsung Electronics", ssdp.ATTR_UPNP_PRESENTATION_URL: url, ssdp.ATTR_UPNP_SERIAL: "00000000", ssdp.ATTR_UPNP_UDN: "uuid:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX", }, ), ) assert result["type"] == data_entry_flow.FlowResultType.FORM assert result["step_id"] == "confirm" assert CONF_URL in result["data_schema"].schema for k in result["data_schema"].schema: if k == CONF_URL: assert k.default() == url
async def test_flow_import_incomplete_discovery(hass: HomeAssistant): """Test config flow: configured through configuration.yaml, but incomplete discovery.""" incomplete_discovery = ssdp.SsdpServiceInfo( ssdp_usn=TEST_USN, ssdp_st=TEST_ST, ssdp_location=TEST_LOCATION, upnp={ # ssdp.ATTR_UPNP_UDN: TEST_UDN, # Not provided. }, ) async def register_callback(hass, callback, match_dict): """Immediately do callback.""" await callback(incomplete_discovery, ssdp.SsdpChange.ALIVE) return MagicMock() with patch( "homeassistant.components.ssdp.async_register_callback", side_effect=register_callback, ), patch( "homeassistant.components.upnp.ssdp.async_get_discovery_info_by_st", return_value=[incomplete_discovery], ): result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_IMPORT} ) assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT assert result["reason"] == "incomplete_discovery"
async def test_ssdp(hass): """Test SSDP discovery initiates config properly.""" url = "http://192.168.100.1/" context = {"source": config_entries.SOURCE_SSDP} result = await hass.config_entries.flow.async_init( DOMAIN, context=context, data=ssdp.SsdpServiceInfo( ssdp_usn="mock_usn", ssdp_st="upnp:rootdevice", ssdp_location="http://192.168.100.1:60957/rootDesc.xml", upnp={ ssdp.ATTR_UPNP_DEVICE_TYPE: "urn:schemas-upnp-org:device:InternetGatewayDevice:1", ssdp.ATTR_UPNP_FRIENDLY_NAME: "Mobile Wi-Fi", ssdp.ATTR_UPNP_MANUFACTURER: "Huawei", ssdp.ATTR_UPNP_MANUFACTURER_URL: "http://www.huawei.com/", ssdp.ATTR_UPNP_MODEL_NAME: "Huawei router", ssdp.ATTR_UPNP_MODEL_NUMBER: "12345678", ssdp.ATTR_UPNP_PRESENTATION_URL: url, ssdp.ATTR_UPNP_SERIAL: "00000000", ssdp.ATTR_UPNP_UDN: "uuid:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX", }, ), ) assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["step_id"] == "user" assert result["data_schema"]({})[CONF_URL] == url
async def test_discovery_via_usb_deconz_already_discovered(detect_mock, hass): """Test usb flow -- deconz discovered.""" result = await hass.config_entries.flow.async_init( "deconz", data=ssdp.SsdpServiceInfo( ssdp_usn="mock_usn", ssdp_st="mock_st", ssdp_location="http://1.2.3.4:80/", upnp={ ATTR_UPNP_MANUFACTURER_URL: "http://www.dresden-elektronik.de", ATTR_UPNP_SERIAL: "0000000000000000", }, ), context={"source": SOURCE_SSDP}, ) await hass.async_block_till_done() discovery_info = usb.UsbServiceInfo( device="/dev/ttyZIGBEE", pid="AAAA", vid="AAAA", serial_number="1234", description="zigbee radio", manufacturer="test", ) result = await hass.config_entries.flow.async_init( "zha", context={"source": SOURCE_USB}, data=discovery_info ) await hass.async_block_till_done() assert result["type"] == "abort" assert result["reason"] == "not_zha_device"
async def test_existing_ssdp(hass: HomeAssistant, service: MagicMock): """Test abort of already existing entry by ssdp.""" MockConfigEntry( domain=DOMAIN, data={ CONF_HOST: "192.168.1.5", CONF_VERIFY_SSL: VERIFY_SSL, CONF_USERNAME: USERNAME, CONF_PASSWORD: PASSWORD, CONF_MAC: MACS, }, unique_id=SERIAL, ).add_to_hass(hass) result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_SSDP}, data=ssdp.SsdpServiceInfo( ssdp_usn="mock_usn", ssdp_st="mock_st", ssdp_location="http://192.168.1.5:5000", upnp={ ssdp.ATTR_UPNP_FRIENDLY_NAME: "mydsm", ssdp.ATTR_UPNP_SERIAL: "001132XXXX59", # Existing in MACS[0], but SSDP does not have `-` }, ), ) assert result["type"] == data_entry_flow.FlowResultType.ABORT assert result["reason"] == "already_configured"
async def test_ssdp_already_configured(hass, mock_panel): """Test if a discovered panel has already been configured.""" MockConfigEntry( domain="konnected", data={"host": "0.0.0.0", "port": 1234}, unique_id="112233445566", ).add_to_hass(hass) mock_panel.get_status.return_value = { "mac": "11:22:33:44:55:66", "model": "Konnected Pro", } result = await hass.config_entries.flow.async_init( config_flow.DOMAIN, context={"source": config_entries.SOURCE_SSDP}, data=ssdp.SsdpServiceInfo( ssdp_usn="mock_usn", ssdp_st="mock_st", ssdp_location="http://0.0.0.0:1234/Device.xml", upnp={ "manufacturer": config_flow.KONN_MANUFACTURER, "modelName": config_flow.KONN_MODEL_PRO, }, ), ) assert result["type"] == "abort" assert result["reason"] == "already_configured"
async def test_ssdp_already_configured(hass): """Test ssdp abort when the router is already configured.""" MockConfigEntry( domain=DOMAIN, data={ CONF_PASSWORD: PASSWORD }, unique_id=SERIAL, ).add_to_hass(hass) result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_SSDP}, data=ssdp.SsdpServiceInfo( ssdp_usn="mock_usn", ssdp_st="mock_st", ssdp_location=SSDP_URL_SLL, upnp={ ssdp.ATTR_UPNP_MODEL_NUMBER: "RBR20", ssdp.ATTR_UPNP_PRESENTATION_URL: URL, ssdp.ATTR_UPNP_SERIAL: SERIAL, }, ), ) assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT assert result["reason"] == "already_configured"
async def test_update_address(hass, aioclient_mock): """Make sure that connection status triggers a dispatcher send.""" config_entry = await setup_deconz_integration(hass, aioclient_mock) gateway = get_gateway_from_config_entry(hass, config_entry) assert gateway.api.host == "1.2.3.4" with patch( "homeassistant.components.deconz.async_setup_entry", return_value=True, ) as mock_setup_entry: await hass.config_entries.flow.async_init( DECONZ_DOMAIN, data=ssdp.SsdpServiceInfo( ssdp_st="mock_st", ssdp_usn="mock_usn", ssdp_location="http://2.3.4.5:80/", upnp={ ATTR_UPNP_MANUFACTURER_URL: DECONZ_MANUFACTURERURL, ATTR_UPNP_SERIAL: BRIDGEID, ATTR_UPNP_UDN: "uuid:456DEF", }, ), context={"source": SOURCE_SSDP}, ) await hass.async_block_till_done() assert gateway.api.host == "2.3.4.5" assert len(mock_setup_entry.mock_calls) == 1
async def test_ssdp_port_5555(hass, service_5555): """Test ssdp step with port 5555.""" result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_SSDP}, data=ssdp.SsdpServiceInfo( ssdp_usn="mock_usn", ssdp_st="mock_st", ssdp_location=SSDP_URL_SLL, upnp={ ssdp.ATTR_UPNP_MODEL_NUMBER: MODELS_PORT_5555[0], ssdp.ATTR_UPNP_PRESENTATION_URL: URL_SSL, ssdp.ATTR_UPNP_SERIAL: SERIAL, }, ), ) assert result["type"] == data_entry_flow.FlowResultType.FORM assert result["step_id"] == "user" result = await hass.config_entries.flow.async_configure( result["flow_id"], {CONF_PASSWORD: PASSWORD}) assert result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY assert result["result"].unique_id == SERIAL assert result["title"] == TITLE assert result["data"].get(CONF_HOST) == HOST assert result["data"].get(CONF_PORT) == PORT_5555 assert result["data"].get(CONF_SSL) is True assert result["data"].get(CONF_USERNAME) == DEFAULT_USER assert result["data"][CONF_PASSWORD] == PASSWORD
async def test_ssdp_discovery_update_configuration(hass, aioclient_mock): """Test if a discovered bridge is configured but updates with new attributes.""" config_entry = await setup_deconz_integration(hass, aioclient_mock) with patch( "homeassistant.components.deconz.async_setup_entry", return_value=True, ) as mock_setup_entry: result = await hass.config_entries.flow.async_init( DECONZ_DOMAIN, data=ssdp.SsdpServiceInfo( ssdp_usn="mock_usn", ssdp_st="mock_st", ssdp_location="http://2.3.4.5:80/", upnp={ ATTR_UPNP_MANUFACTURER_URL: DECONZ_MANUFACTURERURL, ATTR_UPNP_SERIAL: BRIDGEID, }, ), context={"source": SOURCE_SSDP}, ) await hass.async_block_till_done() assert result["type"] == RESULT_TYPE_ABORT assert result["reason"] == "already_configured" assert config_entry.data[CONF_HOST] == "2.3.4.5" assert len(mock_setup_entry.mock_calls) == 1
async def test_ssdp_ipv6(hass): """Test ssdp abort when using a ipv6 address.""" MockConfigEntry( domain=DOMAIN, data={ CONF_PASSWORD: PASSWORD }, unique_id=SERIAL, ).add_to_hass(hass) result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_SSDP}, data=ssdp.SsdpServiceInfo( ssdp_usn="mock_usn", ssdp_st="mock_st", ssdp_location=SSDP_URLipv6, upnp={ ssdp.ATTR_UPNP_MODEL_NUMBER: "RBR20", ssdp.ATTR_UPNP_PRESENTATION_URL: URL, ssdp.ATTR_UPNP_SERIAL: SERIAL, }, ), ) assert result["type"] == data_entry_flow.FlowResultType.ABORT assert result["reason"] == "not_ipv4_address"
async def test_form_ssdp_existing_entry_no_port_https(hass: HomeAssistant): """Test we update the ip of an existing entry from ssdp with no port and https.""" entry = MockConfigEntry( domain=DOMAIN, data={CONF_HOST: f"https://{MOCK_HOSTNAME}/{ISY_URL_POSTFIX}"}, unique_id=MOCK_UUID, ) entry.add_to_hass(hass) with patch(PATCH_CONNECTION, return_value=MOCK_CONFIG_RESPONSE): result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_SSDP}, data=ssdp.SsdpServiceInfo( ssdp_usn="mock_usn", ssdp_st="mock_st", ssdp_location=f"https://3.3.3.3/{ISY_URL_POSTFIX}", upnp={ ssdp.ATTR_UPNP_FRIENDLY_NAME: "myisy", ssdp.ATTR_UPNP_UDN: f"{UDN_UUID_PREFIX}{MOCK_UUID}", }, ), ) await hass.async_block_till_done() assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT assert result["reason"] == "already_configured" assert entry.data[CONF_HOST] == f"https://3.3.3.3:443/{ISY_URL_POSTFIX}"
async def test_form_ssdp_gets_form_with_ignored_entry(hass): """Test we can still setup if there is an ignored entry.""" entry = MockConfigEntry( domain=UNIFI_DOMAIN, data={"not_controller_key": None}, source=config_entries.SOURCE_IGNORE, ) entry.add_to_hass(hass) result = await hass.config_entries.flow.async_init( UNIFI_DOMAIN, context={"source": config_entries.SOURCE_SSDP}, data=ssdp.SsdpServiceInfo( ssdp_usn="mock_usn", ssdp_st="mock_st", ssdp_location="http://1.2.3.4:41417/rootDesc.xml", upnp={ "friendlyName": "UniFi Dream Machine New", "modelDescription": "UniFi Dream Machine Pro", "serialNumber": "e0:63:da:20:14:a9", }, ), ) assert result["type"] == "form" assert result["step_id"] == "user" assert result["errors"] == {} context = next(flow["context"] for flow in hass.config_entries.flow.async_progress() if flow["flow_id"] == result["flow_id"]) assert context["title_placeholders"] == { "host": "1.2.3.4", "site": "default", }
async def test_form_ssdp_already_configured(hass: HomeAssistant) -> None: """Test ssdp abort when the serial number is already configured.""" MockConfigEntry( domain=DOMAIN, data={ CONF_HOST: f"http://{MOCK_HOSTNAME}{ISY_URL_POSTFIX}" }, unique_id=MOCK_UUID, ).add_to_hass(hass) result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_SSDP}, data=ssdp.SsdpServiceInfo( ssdp_usn="mock_usn", ssdp_st="mock_st", ssdp_location=f"http://{MOCK_HOSTNAME}{ISY_URL_POSTFIX}", upnp={ ssdp.ATTR_UPNP_FRIENDLY_NAME: "myisy", ssdp.ATTR_UPNP_UDN: f"{UDN_UUID_PREFIX}{MOCK_UUID}", }, ), ) assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
async def test_form_ssdp(hass): """Test we get the form with ssdp source.""" result = await hass.config_entries.flow.async_init( UNIFI_DOMAIN, context={"source": config_entries.SOURCE_SSDP}, data=ssdp.SsdpServiceInfo( ssdp_usn="mock_usn", ssdp_st="mock_st", ssdp_location="http://192.168.208.1:41417/rootDesc.xml", upnp={ "friendlyName": "UniFi Dream Machine", "modelDescription": "UniFi Dream Machine Pro", "serialNumber": "e0:63:da:20:14:a9", }, ), ) assert result["type"] == "form" assert result["step_id"] == "user" assert result["errors"] == {} context = next(flow["context"] for flow in hass.config_entries.flow.async_progress() if flow["flow_id"] == result["flow_id"]) assert context["title_placeholders"] == { "host": "192.168.208.1", "site": "default", }
async def test_form_ssdp_aborts_if_serial_already_exists(hass): """Test we abort if the serial is already configured.""" entry = MockConfigEntry( domain=UNIFI_DOMAIN, data={"controller": { "host": "1.2.3.4", "site": "site_id" }}, unique_id="e0:63:da:20:14:a9", ) entry.add_to_hass(hass) result = await hass.config_entries.flow.async_init( UNIFI_DOMAIN, context={"source": config_entries.SOURCE_SSDP}, data=ssdp.SsdpServiceInfo( ssdp_usn="mock_usn", ssdp_st="mock_st", ssdp_location="http://192.168.208.1:41417/rootDesc.xml", upnp={ "friendlyName": "UniFi Dream Machine", "modelDescription": "UniFi Dream Machine Pro", "serialNumber": "e0:63:da:20:14:a9", }, ), ) assert result["type"] == "abort" assert result["reason"] == "already_configured"
async def test_form_ssdp_aborts_before_checking_remoteid_if_host_known(hass): """Test we abort without connecting if the host is already known.""" config_entry = MockConfigEntry( domain=DOMAIN, data={"host": "2.2.2.2", "name": "any"}, ) config_entry.add_to_hass(hass) config_entry_without_host = MockConfigEntry( domain=DOMAIN, data={"name": "other"}, ) config_entry_without_host.add_to_hass(hass) harmonyapi = _get_mock_harmonyapi(connect=True) with patch( "homeassistant.components.harmony.util.HarmonyAPI", return_value=harmonyapi, ): result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_SSDP}, data=ssdp.SsdpServiceInfo( ssdp_usn="mock_usn", ssdp_st="mock_st", ssdp_location="http://2.2.2.2:8088/description", upnp={ "friendlyName": "Harmony Hub", }, ), ) assert result["type"] == "abort"
async def test_ssdp_discovery_update_configuration(hass, aioclient_mock): """Test if a discovered bridge is configured and updated with new host.""" create_mock_api_discovery(aioclient_mock, [("1.1.1.1", "aabbccddeeff")]) entry = MockConfigEntry(domain="hue", unique_id="aabbccddeeff", data={"host": "0.0.0.0"}) entry.add_to_hass(hass) result = await hass.config_entries.flow.async_init( const.DOMAIN, context={"source": config_entries.SOURCE_SSDP}, data=ssdp.SsdpServiceInfo( ssdp_usn="mock_usn", ssdp_st="mock_st", ssdp_location="http://1.1.1.1/", upnp={ ssdp.ATTR_UPNP_MANUFACTURER_URL: config_flow.HUE_MANUFACTURERURL[0], ssdp.ATTR_UPNP_SERIAL: "aabbccddeeff", }, ), ) assert result["type"] == "abort" assert result["reason"] == "already_configured" assert entry.data["host"] == "1.1.1.1"
async def test_ssdp_discovery_dont_update_existing_hassio_configuration( hass, aioclient_mock ): """Test to ensure the SSDP discovery does not update an Hass.io entry.""" config_entry = await setup_deconz_integration( hass, aioclient_mock, source=SOURCE_HASSIO ) result = await hass.config_entries.flow.async_init( DECONZ_DOMAIN, data=ssdp.SsdpServiceInfo( ssdp_usn="mock_usn", ssdp_st="mock_st", ssdp_location="http://1.2.3.4:80/", upnp={ ATTR_UPNP_MANUFACTURER_URL: DECONZ_MANUFACTURERURL, ATTR_UPNP_SERIAL: BRIDGEID, }, ), context={"source": SOURCE_SSDP}, ) assert result["type"] == RESULT_TYPE_ABORT assert result["reason"] == "already_configured" assert config_entry.data[CONF_HOST] == "1.2.3.4"
async def test_become_available( hass: HomeAssistant, upnp_factory_mock: Mock, ssdp_scanner_mock: Mock, disconnected_source_mock: None, ) -> None: """Test a device becoming available after the entity is constructed.""" # Mock device is now available. upnp_factory_mock.async_create_device.side_effect = None upnp_factory_mock.async_create_device.reset_mock() # Send an SSDP notification from the now alive device ssdp_callback = ssdp_scanner_mock.async_register_callback.call_args.args[0] await ssdp_callback( ssdp.SsdpServiceInfo( ssdp_usn=MOCK_DEVICE_USN, ssdp_location=NEW_DEVICE_LOCATION, ssdp_st=MOCK_DEVICE_TYPE, upnp={}, ), ssdp.SsdpChange.ALIVE, ) await hass.async_block_till_done() # Check device was created from the supplied URL upnp_factory_mock.async_create_device.assert_awaited_once_with(NEW_DEVICE_LOCATION) # Quick check of the state to verify the entity has a connected DmsDevice await assert_source_available(hass)
async def test_config_flow_ssdp(hass): """Successful flow initialized by ssdp discovery.""" result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_SSDP}, data=ssdp.SsdpServiceInfo( ssdp_usn="mock_usn", ssdp_st="mock_st", ssdp_location=TEST_SSDP_LOCATION, upnp={ ssdp.ATTR_UPNP_MANUFACTURER: TEST_MANUFACTURER, ssdp.ATTR_UPNP_MODEL_NAME: TEST_MODEL, ssdp.ATTR_UPNP_SERIAL: TEST_SERIALNUMBER, }, ), ) assert result["type"] == "form" assert result["step_id"] == "confirm" result = await hass.config_entries.flow.async_configure( result["flow_id"], {}, ) assert result["type"] == "create_entry" assert result["title"] == TEST_NAME assert result["data"] == { CONF_HOST: TEST_HOST, CONF_MODEL: TEST_MODEL, CONF_TYPE: TEST_RECEIVER_TYPE, CONF_MANUFACTURER: TEST_MANUFACTURER, CONF_SERIAL_NUMBER: TEST_SERIALNUMBER, }
def _generate_fake_ssdp_listener(*args, **kwargs): info = None if not no_device: info = ssdp.SsdpServiceInfo( ssdp_usn="", ssdp_st=scanner.SSDP_ST, upnp={}, ssdp_headers=capabilities or CAPABILITIES, ) return _patched_ssdp_listener(info, *args, **kwargs)
async def test_service_info_compatibility(hass, caplog): """Test compatibility with old-style dict. To be removed in 2022.6 """ discovery_info = ssdp.SsdpServiceInfo( ssdp_st="mock-st", ssdp_location="http://1.1.1.1", ssdp_usn="uuid:mock-udn::mock-st", ssdp_server="mock-server", ssdp_ext="", ssdp_headers=_ssdp_headers( { "st": "mock-st", "location": "http://1.1.1.1", "usn": "uuid:mock-udn::mock-st", "server": "mock-server", "ext": "", } ), upnp={ssdp.ATTR_UPNP_DEVICE_TYPE: "ABC"}, ) with patch("homeassistant.helpers.frame._REPORTED_INTEGRATIONS", set()): assert discovery_info["ssdp_st"] == "mock-st" assert "Detected integration that accessed discovery_info['ssdp_st']" in caplog.text with patch("homeassistant.helpers.frame._REPORTED_INTEGRATIONS", set()): assert discovery_info.get("ssdp_location") == "http://1.1.1.1" assert ( "Detected integration that accessed discovery_info.get('ssdp_location')" in caplog.text ) with patch("homeassistant.helpers.frame._REPORTED_INTEGRATIONS", set()): assert "ssdp_usn" in discovery_info assert ( "Detected integration that accessed discovery_info.__contains__('ssdp_usn')" in caplog.text ) # Root item assert discovery_info["ssdp_usn"] == "uuid:mock-udn::mock-st" assert discovery_info.get("ssdp_usn") == "uuid:mock-udn::mock-st" assert "ssdp_usn" in discovery_info # SSDP header assert discovery_info["st"] == "mock-st" assert discovery_info.get("st") == "mock-st" assert "st" in discovery_info # UPnP item assert discovery_info[ssdp.ATTR_UPNP_DEVICE_TYPE] == "ABC" assert discovery_info.get(ssdp.ATTR_UPNP_DEVICE_TYPE) == "ABC" assert ssdp.ATTR_UPNP_DEVICE_TYPE in discovery_info
def _async_start_flow(*_) -> None: discovery_flow.async_create_flow( self._hass, DOMAIN, context={"source": config_entries.SOURCE_SSDP}, data=ssdp.SsdpServiceInfo( ssdp_usn="", ssdp_st=SSDP_ST, ssdp_headers=response, upnp={}, ), )