예제 #1
0
async def test_scan_match_upnp_devicedesc(hass, aioclient_mock, key):
    """Test matching based on UPnP device description data."""
    aioclient_mock.get(
        "http://1.1.1.1",
        text=f"""
<root>
  <device>
    <{key}>Paulus</{key}>
  </device>
</root>
    """,
    )
    scanner = ssdp.Scanner(hass, {"mock-domain": [{key: "Paulus"}]})

    with patch(
            "netdisco.ssdp.scan",
            return_value=[
                Mock(st="mock-st", location="http://1.1.1.1", values={})
            ],
    ), patch.object(hass.config_entries.flow,
                    "async_init",
                    return_value=mock_coro()) as mock_init:
        await scanner.async_scan(None)

    assert len(mock_init.mock_calls) == 1
    assert mock_init.mock_calls[0][1][0] == "mock-domain"
    assert mock_init.mock_calls[0][2]["context"] == {"source": "ssdp"}
예제 #2
0
async def test_scan_match_device_type(hass, aioclient_mock):
    """Test matching based on ST."""
    aioclient_mock.get('http://1.1.1.1',
                       text="""
<root>
  <device>
    <deviceType>Paulus</deviceType>
  </device>
</root>
    """)
    scanner = ssdp.Scanner(hass)

    with patch('netdisco.ssdp.scan',
               return_value=[
                   Mock(st="mock-st", location='http://1.1.1.1')
               ]), patch.dict(gn_ssdp.SSDP['device_type'],
                              {'Paulus': ['mock-domain']}), patch.object(
                                  hass.config_entries.flow,
                                  'async_init',
                                  return_value=mock_coro()) as mock_init:
        await scanner.async_scan(None)

    assert len(mock_init.mock_calls) == 1
    assert mock_init.mock_calls[0][1][0] == 'mock-domain'
    assert mock_init.mock_calls[0][2]['context'] == {'source': 'ssdp'}
예제 #3
0
async def test_scan_match_upnp_devicedesc(hass, aioclient_mock, key):
    """Test matching based on UPnP device description data."""
    aioclient_mock.get(
        "http://1.1.1.1",
        text=f"""
<root>
  <device>
    <{key}>Paulus</{key}>
  </device>
</root>
    """,
    )
    scanner = ssdp.Scanner(hass, {"mock-domain": [{key: "Paulus"}]})

    async def _inject_entry(*args, **kwargs):
        scanner.async_store_entry(
            Mock(st="mock-st", location="http://1.1.1.1", values={})
        )

    with patch(
        "homeassistant.components.ssdp.async_search",
        side_effect=_inject_entry,
    ), patch.object(
        hass.config_entries.flow, "async_init", return_value=mock_coro()
    ) as mock_init:
        await scanner.async_scan(None)

    assert len(mock_init.mock_calls) == 1
    assert mock_init.mock_calls[0][1][0] == "mock-domain"
    assert mock_init.mock_calls[0][2]["context"] == {"source": "ssdp"}
예제 #4
0
async def test_scan_match_device_type(hass, aioclient_mock):
    """Test matching based on ST."""
    aioclient_mock.get(
        "http://1.1.1.1",
        text="""
<root>
  <device>
    <deviceType>Paulus</deviceType>
  </device>
</root>
    """,
    )
    scanner = ssdp.Scanner(hass)

    with patch(
            "netdisco.ssdp.scan",
            return_value=[Mock(st="mock-st", location="http://1.1.1.1")],
    ), patch.dict(gn_ssdp.SSDP["device_type"],
                  {"Paulus": ["mock-domain"]}), patch.object(
                      hass.config_entries.flow,
                      "async_init",
                      return_value=mock_coro()) as mock_init:
        await scanner.async_scan(None)

    assert len(mock_init.mock_calls) == 1
    assert mock_init.mock_calls[0][1][0] == "mock-domain"
    assert mock_init.mock_calls[0][2]["context"] == {"source": "ssdp"}
예제 #5
0
async def test_scan_not_all_match(hass, aioclient_mock):
    """Test match fails if some specified attribute values differ."""
    aioclient_mock.get(
        "http://1.1.1.1",
        text=f"""
<root>
  <device>
    <deviceType>Paulus</deviceType>
    <manufacturer>Paulus</manufacturer>
  </device>
</root>
    """,
    )
    scanner = ssdp.Scanner(hass)

    with patch(
        "netdisco.ssdp.scan",
        return_value=[Mock(st="mock-st", location="http://1.1.1.1")],
    ), patch.dict(
        gn_ssdp.SSDP,
        {"mock-domain": [{"deviceType": "Paulus", "manufacturer": "Not-Paulus"}]},
    ), patch.object(
        hass.config_entries.flow, "async_init", return_value=mock_coro()
    ) as mock_init:
        await scanner.async_scan(None)

    assert not mock_init.mock_calls
예제 #6
0
async def test_scan_match_st(hass, caplog):
    """Test matching based on ST."""
    scanner = ssdp.Scanner(hass, {"mock-domain": [{"st": "mock-st"}]})

    with patch(
            "netdisco.ssdp.scan",
            return_value=[
                Mock(
                    st="mock-st",
                    location=None,
                    values={
                        "usn": "mock-usn",
                        "server": "mock-server",
                        "ext": ""
                    },
                )
            ],
    ), patch.object(hass.config_entries.flow,
                    "async_init",
                    return_value=mock_coro()) as mock_init:
        await scanner.async_scan(None)

    assert len(mock_init.mock_calls) == 1
    assert mock_init.mock_calls[0][1][0] == "mock-domain"
    assert mock_init.mock_calls[0][2]["context"] == {"source": "ssdp"}
    assert mock_init.mock_calls[0][2]["data"] == {
        ssdp.ATTR_SSDP_ST: "mock-st",
        ssdp.ATTR_SSDP_LOCATION: None,
        ssdp.ATTR_SSDP_USN: "mock-usn",
        ssdp.ATTR_SSDP_SERVER: "mock-server",
        ssdp.ATTR_SSDP_EXT: "",
    }
    assert "Failed to fetch ssdp data" not in caplog.text
예제 #7
0
async def test_scan_not_all_present(hass, aioclient_mock):
    """Test match fails if some specified attributes are not present."""
    aioclient_mock.get(
        "http://1.1.1.1",
        text="""
<root>
  <device>
    <deviceType>Paulus</deviceType>
  </device>
</root>
    """,
    )
    scanner = ssdp.Scanner(
        hass,
        {
            "mock-domain": [{
                ssdp.ATTR_UPNP_DEVICE_TYPE: "Paulus",
                ssdp.ATTR_UPNP_MANUFACTURER: "Paulus",
            }]
        },
    )

    with patch(
            "netdisco.ssdp.scan",
            return_value=[
                Mock(st="mock-st", location="http://1.1.1.1", values={})
            ],
    ), patch.object(hass.config_entries.flow,
                    "async_init",
                    return_value=mock_coro()) as mock_init:
        await scanner.async_scan(None)

    assert not mock_init.mock_calls
예제 #8
0
async def test_scan_description_fetch_fail(hass, aioclient_mock, exc):
    """Test failing to fetch description."""
    aioclient_mock.get('http://1.1.1.1', exc=exc)
    scanner = ssdp.Scanner(hass)

    with patch('netdisco.ssdp.scan',
               return_value=[Mock(st="mock-st", location='http://1.1.1.1')]):
        await scanner.async_scan(None)
예제 #9
0
async def test_scan_description_fetch_fail(hass, aioclient_mock, exc):
    """Test failing to fetch description."""
    aioclient_mock.get("http://1.1.1.1", exc=exc)
    scanner = ssdp.Scanner(hass, {})

    with patch(
        "netdisco.ssdp.scan",
        return_value=[Mock(st="mock-st", location="http://1.1.1.1", values={})],
    ):
        await scanner.async_scan(None)
예제 #10
0
async def test_scan_description_parse_fail(hass, aioclient_mock):
    """Test invalid XML."""
    aioclient_mock.get('http://1.1.1.1', text="""
<root>INVALIDXML
    """)
    scanner = ssdp.Scanner(hass)

    with patch('netdisco.ssdp.scan',
               return_value=[Mock(st="mock-st", location='http://1.1.1.1')]):
        await scanner.async_scan(None)
예제 #11
0
async def test_invalid_characters(hass, aioclient_mock):
    """Test that we replace bad characters with placeholders."""
    aioclient_mock.get(
        "http://1.1.1.1",
        text="""
<root>
  <device>
    <deviceType>ABC</deviceType>
    <serialNumber>\xff\xff\xff\xff</serialNumber>
  </device>
</root>
    """,
    )
    scanner = ssdp.Scanner(
        hass,
        {
            "mock-domain": [
                {
                    ssdp.ATTR_UPNP_DEVICE_TYPE: "ABC",
                }
            ]
        },
    )

    async def _mock_async_scan(*args, async_callback=None, **kwargs):
        await async_callback(
            {
                "st": "mock-st",
                "location": "http://1.1.1.1",
            }
        )

    with patch(
        "homeassistant.components.ssdp.async_search",
        side_effect=_mock_async_scan,
    ), patch.object(
        hass.config_entries.flow, "async_init", return_value=mock_coro()
    ) as mock_init:
        await scanner.async_scan(None)

    assert len(mock_init.mock_calls) == 1
    assert mock_init.mock_calls[0][1][0] == "mock-domain"
    assert mock_init.mock_calls[0][2]["context"] == {
        "source": config_entries.SOURCE_SSDP
    }
    assert mock_init.mock_calls[0][2]["data"] == {
        "ssdp_location": "http://1.1.1.1",
        "ssdp_st": "mock-st",
        "deviceType": "ABC",
        "serialNumber": "ÿÿÿÿ",
    }
예제 #12
0
async def test_scan_match_st(hass):
    """Test matching based on ST."""
    scanner = ssdp.Scanner(hass)

    with patch(
        "netdisco.ssdp.scan", return_value=[Mock(st="mock-st", location=None)]
    ), patch.dict(gn_ssdp.SSDP, {"mock-domain": [{"st": "mock-st"}]}), patch.object(
        hass.config_entries.flow, "async_init", return_value=mock_coro()
    ) as mock_init:
        await scanner.async_scan(None)

    assert len(mock_init.mock_calls) == 1
    assert mock_init.mock_calls[0][1][0] == "mock-domain"
    assert mock_init.mock_calls[0][2]["context"] == {"source": "ssdp"}
예제 #13
0
async def test_scan_description_fetch_fail(hass, aioclient_mock, exc):
    """Test failing to fetch description."""
    aioclient_mock.get("http://1.1.1.1", exc=exc)
    scanner = ssdp.Scanner(hass, {})

    async def _inject_entry(*args, **kwargs):
        scanner.async_store_entry(
            Mock(st="mock-st", location="http://1.1.1.1", values={})
        )

    with patch(
        "homeassistant.components.ssdp.async_search",
        side_effect=_inject_entry,
    ):
        await scanner.async_scan(None)
예제 #14
0
async def test_scan_description_parse_fail(hass, aioclient_mock):
    """Test invalid XML."""
    aioclient_mock.get(
        "http://1.1.1.1",
        text="""
<root>INVALIDXML
    """,
    )
    scanner = ssdp.Scanner(hass, {})

    with patch(
        "netdisco.ssdp.scan",
        return_value=[Mock(st="mock-st", location="http://1.1.1.1", values={})],
    ):
        await scanner.async_scan(None)
예제 #15
0
async def test_scan_match_st(hass):
    """Test matching based on ST."""
    scanner = ssdp.Scanner(hass)

    with patch('netdisco.ssdp.scan',
               return_value=[Mock(st="mock-st", location=None)]), patch.dict(
                   gn_ssdp.SSDP['st'],
                   {'mock-st': ['mock-domain']}), patch.object(
                       hass.config_entries.flow,
                       'async_init',
                       return_value=mock_coro()) as mock_init:
        await scanner.async_scan(None)

    assert len(mock_init.mock_calls) == 1
    assert mock_init.mock_calls[0][1][0] == 'mock-domain'
    assert mock_init.mock_calls[0][2]['context'] == {'source': 'ssdp'}
예제 #16
0
async def test_scan_description_fetch_fail(hass, aioclient_mock, exc):
    """Test failing to fetch description."""
    aioclient_mock.get("http://1.1.1.1", exc=exc)
    scanner = ssdp.Scanner(hass, {})

    async def _mock_async_scan(*args, async_callback=None, **kwargs):
        await async_callback(
            {
                "st": "mock-st",
                "location": "http://1.1.1.1",
            }
        )

    with patch(
        "homeassistant.components.ssdp.async_search",
        side_effect=_mock_async_scan,
    ):
        await scanner.async_scan(None)
예제 #17
0
async def test_unexpected_exception_while_fetching(hass, aioclient_mock, caplog):
    """Test unexpected exception while fetching."""
    aioclient_mock.get(
        "http://1.1.1.1",
        text="""
<root>
  <device>
    <deviceType>ABC</deviceType>
    <serialNumber>\xff\xff\xff\xff</serialNumber>
  </device>
</root>
    """,
    )
    scanner = ssdp.Scanner(
        hass,
        {
            "mock-domain": [
                {
                    ssdp.ATTR_UPNP_DEVICE_TYPE: "ABC",
                }
            ]
        },
    )

    async def _mock_async_scan(*args, async_callback=None, **kwargs):
        await async_callback(
            {
                "st": "mock-st",
                "location": "http://1.1.1.1",
            }
        )

    with patch(
        "homeassistant.components.ssdp.ElementTree.fromstring", side_effect=ValueError
    ), patch(
        "homeassistant.components.ssdp.async_search",
        side_effect=_mock_async_scan,
    ), patch.object(
        hass.config_entries.flow, "async_init", return_value=mock_coro()
    ) as mock_init:
        await scanner.async_scan(None)

    assert len(mock_init.mock_calls) == 0
    assert "Failed to fetch ssdp data from: http://1.1.1.1" in caplog.text
예제 #18
0
async def test_scan_not_all_match(hass, aioclient_mock):
    """Test match fails if some specified attribute values differ."""
    aioclient_mock.get(
        "http://1.1.1.1",
        text="""
<root>
  <device>
    <deviceType>Paulus</deviceType>
    <manufacturer>Paulus</manufacturer>
  </device>
</root>
    """,
    )
    scanner = ssdp.Scanner(
        hass,
        {
            "mock-domain": [
                {
                    ssdp.ATTR_UPNP_DEVICE_TYPE: "Paulus",
                    ssdp.ATTR_UPNP_MANUFACTURER: "Not-Paulus",
                }
            ]
        },
    )

    async def _mock_async_scan(*args, async_callback=None, **kwargs):
        await async_callback(
            {
                "st": "mock-st",
                "location": "http://1.1.1.1",
            }
        )

    with patch(
        "homeassistant.components.ssdp.async_search",
        side_effect=_mock_async_scan,
    ), patch.object(
        hass.config_entries.flow, "async_init", return_value=mock_coro()
    ) as mock_init:
        await scanner.async_scan(None)

    assert not mock_init.mock_calls
예제 #19
0
async def test_scan_description_parse_fail(hass, aioclient_mock):
    """Test invalid XML."""
    aioclient_mock.get(
        "http://1.1.1.1",
        text="""
<root>INVALIDXML
    """,
    )
    scanner = ssdp.Scanner(hass, {})

    async def _inject_entry(*args, **kwargs):
        scanner.async_store_entry(
            Mock(st="mock-st", location="http://1.1.1.1", values={})
        )

    with patch(
        "homeassistant.components.ssdp.async_search",
        side_effect=_inject_entry,
    ):
        await scanner.async_scan(None)
예제 #20
0
async def test_invalid_characters(hass, aioclient_mock):
    """Test that we replace bad characters with placeholders."""
    aioclient_mock.get(
        "http://1.1.1.1",
        text="""
<root>
  <device>
    <deviceType>ABC</deviceType>
    <serialNumber>\xff\xff\xff\xff</serialNumber>
  </device>
</root>
    """,
    )
    scanner = ssdp.Scanner(
        hass,
        {"mock-domain": [{
            ssdp.ATTR_UPNP_DEVICE_TYPE: "ABC",
        }]},
    )

    with patch(
            "netdisco.ssdp.scan",
            return_value=[
                Mock(st="mock-st", location="http://1.1.1.1", values={})
            ],
    ), patch.object(hass.config_entries.flow,
                    "async_init",
                    return_value=mock_coro()) as mock_init:
        await scanner.async_scan(None)

    assert len(mock_init.mock_calls) == 1
    assert mock_init.mock_calls[0][1][0] == "mock-domain"
    assert mock_init.mock_calls[0][2]["context"] == {"source": "ssdp"}
    assert mock_init.mock_calls[0][2]["data"] == {
        "ssdp_location": "http://1.1.1.1",
        "ssdp_st": "mock-st",
        "deviceType": "ABC",
        "serialNumber": "ÿÿÿÿ",
    }
예제 #21
0
async def test_scan_match_upnp_devicedesc(hass, aioclient_mock, key):
    """Test matching based on UPnP device description data."""
    aioclient_mock.get(
        "http://1.1.1.1",
        text=f"""
<root>
  <device>
    <{key}>Paulus</{key}>
  </device>
</root>
    """,
    )
    scanner = ssdp.Scanner(hass, {"mock-domain": [{key: "Paulus"}]})

    async def _mock_async_scan(*args, async_callback=None, **kwargs):
        for _ in range(5):
            await async_callback(
                {
                    "st": "mock-st",
                    "location": "http://1.1.1.1",
                }
            )

    with patch(
        "homeassistant.components.ssdp.async_search",
        side_effect=_mock_async_scan,
    ), patch.object(
        hass.config_entries.flow, "async_init", return_value=mock_coro()
    ) as mock_init:
        await scanner.async_scan(None)

    # If we get duplicate respones, ensure we only look it up once
    assert len(aioclient_mock.mock_calls) == 1
    assert len(mock_init.mock_calls) == 1
    assert mock_init.mock_calls[0][1][0] == "mock-domain"
    assert mock_init.mock_calls[0][2]["context"] == {
        "source": config_entries.SOURCE_SSDP
    }
예제 #22
0
async def test_scan_description_parse_fail(hass, aioclient_mock):
    """Test invalid XML."""
    aioclient_mock.get(
        "http://1.1.1.1",
        text="""
<root>INVALIDXML
    """,
    )
    scanner = ssdp.Scanner(hass, {})

    async def _mock_async_scan(*args, async_callback=None, **kwargs):
        await async_callback(
            {
                "st": "mock-st",
                "location": "http://1.1.1.1",
            }
        )

    with patch(
        "homeassistant.components.ssdp.async_search",
        side_effect=_mock_async_scan,
    ):
        await scanner.async_scan(None)
예제 #23
0
async def test_scan_match_st(hass, caplog):
    """Test matching based on ST."""
    scanner = ssdp.Scanner(hass, {"mock-domain": [{"st": "mock-st"}]})

    async def _mock_async_scan(*args, async_callback=None, **kwargs):
        await async_callback(
            {
                "st": "mock-st",
                "location": None,
                "usn": "mock-usn",
                "server": "mock-server",
                "ext": "",
            }
        )

    with patch(
        "homeassistant.components.ssdp.async_search",
        side_effect=_mock_async_scan,
    ), patch.object(
        hass.config_entries.flow, "async_init", return_value=mock_coro()
    ) as mock_init:
        await scanner.async_scan(None)

    assert len(mock_init.mock_calls) == 1
    assert mock_init.mock_calls[0][1][0] == "mock-domain"
    assert mock_init.mock_calls[0][2]["context"] == {
        "source": config_entries.SOURCE_SSDP
    }
    assert mock_init.mock_calls[0][2]["data"] == {
        ssdp.ATTR_SSDP_ST: "mock-st",
        ssdp.ATTR_SSDP_LOCATION: None,
        ssdp.ATTR_SSDP_USN: "mock-usn",
        ssdp.ATTR_SSDP_SERVER: "mock-server",
        ssdp.ATTR_SSDP_EXT: "",
    }
    assert "Failed to fetch ssdp data" not in caplog.text