MatthewFlamm / pytest-homeassistant-custom-component

Package to automatically extract testing plugins from Home Assistant for custom component testing
MIT License
67 stars 10 forks source link

pytest_socket.SocketBlockedError: A test tried to use socket.socket. #154

Open fishy242 opened 1 year ago

fishy242 commented 1 year ago

Hi,

I shall say at the very beginning, I am new to the home assistant custom component development and new to python too, so I think I get something missing but I cannot find any result from google.

What I have done so far is just clone this repo, setup a venv by python -m venv venv, activate the venv and then to pip install pytest-homeassistant-custom-componet. Every things look OK so far. But when I try to run pytest in this repo, I get the following error

――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― ERROR at setup of test_sensor ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――

fixturedef = <FixtureDef argname='event_loop' scope='function' baseid=''>, request = <SubRequest 'event_loop' for <Function test_sensor>>

    @pytest.hookimpl(hookwrapper=True)
    def pytest_fixture_setup(
        fixturedef: FixtureDef, request: SubRequest
    ) -> Optional[object]:
        """Adjust the event loop policy when an event loop is produced."""
        if fixturedef.argname == "event_loop":
            outcome = yield
>           loop = outcome.get_result()

venv\lib\site-packages\pytest_asyncio\plugin.py:399:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
venv\lib\site-packages\pytest_asyncio\plugin.py:513: in event_loop
    loop = asyncio.get_event_loop_policy().new_event_loop()
venv\lib\site-packages\homeassistant\runner.py:104: in new_event_loop
    loop: asyncio.AbstractEventLoop = super().new_event_loop()
C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.10_3.10.2800.0_x64__qbz5n2kfra8p0\lib\asyncio\events.py:673: in new_event_loop
    return self._loop_factory()
C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.10_3.10.2800.0_x64__qbz5n2kfra8p0\lib\asyncio\windows_events.py:315: in __init__
    super().__init__(proactor)
C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.10_3.10.2800.0_x64__qbz5n2kfra8p0\lib\asyncio\proactor_events.py:636: in __init__
    self._make_self_pipe()
C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.10_3.10.2800.0_x64__qbz5n2kfra8p0\lib\asyncio\proactor_events.py:767: in _make_self_pipe
    self._ssock, self._csock = socket.socketpair()
C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.10_3.10.2800.0_x64__qbz5n2kfra8p0\lib\socket.py:630: in socketpair
    lsock = socket(family, type, proto)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

cls = <class 'pytest_socket.disable_socket.<locals>.GuardedSocket'>, family = <AddressFamily.AF_INET: 2>, type = <SocketKind.SOCK_STREAM: 1>, proto = 0, fileno = None
    def __new__(cls, family=-1, type=-1, proto=-1, fileno=None):
        if _is_unix_socket(family) and allow_unix_socket:
            return super().__new__(cls, family, type, proto, fileno)

>       raise SocketBlockedError()
E       pytest_socket.SocketBlockedError: A test tried to use socket.socket.

venv\lib\site-packages\pytest_socket.py:80: SocketBlockedError

I get the same error even on my dummy test which just contain assert(True). Apparently I didn't try to open any socket. How can I get rid of this issue?

Your help and advice would be much appreciated. Thanks!

MatthewFlamm commented 1 year ago

See #96, which is probably related.

Are you defining any fixtures in your test? It looks like it is failing during setup of the test.

IATkachenko commented 1 year ago

@MatthewFlamm, hello.

This issue is relevant for tests in https://github.com/MatthewFlamm/pytest-homeassistant-custom-component/tree/master/tests without any modifications at Windows machines. Linux machines is not affected.

Looks like Windows is using AF_INET socket for creating asyncio, so https://github.com/MatthewFlamm/pytest-homeassistant-custom-component/blob/ee2dc5641df608d47bbbdaf9e2fca59398f0d8b4/src/pytest_homeassistant_custom_component/plugins.py#L153 could not allow it. (after commenting just this line all works well by obvious reason)

MatthewFlamm commented 1 year ago

If this is indeed a Windows difference, homeassistant core does not support or test on Windows, so this is use case is unsupported. You may need to use a fixture to enable the needed socket, but I am not familiar with this.

IATkachenko commented 1 year ago

The problem is not in HomeAssistant code base, but in pytest-soket + asyncio for Windows... pytest-homeassistant-custom-component is blocking socket usage for tests, like HA https://github.com/home-assistant/core/blob/28d85bc405136cfeec3dcebaeb8705102aaa2294/tests/conftest.py#L149 ,so any usage of hass in tests will cause SocketBlockedError at Windows machines.

Special fixture for enabling socket looks promising, but is should be loaded in hass fixture to avoid unnecessary calls or test arguments...

MatthewFlamm commented 1 year ago

This package simply extracts the testing from homeassistant core with very light modifications for ease of use. If running in Windows isn't supported in homeassistant core, then it won't be supported here either. We don't mess with hass fixture in this package for this reason.

fishy242 commented 1 year ago

If Windows is not suppose to work, any advice on the dev environment? Simply wsl? Or inside the devcontainer of the official home assistance code dev environment? The file structure come out from cookiecutter template seems not so ideal to use in Home assistant core devcontainer.

Thanks for pointing the right direction to beginner as me:)

IATkachenko commented 1 year ago

@fishy242, for tests from Windows I'm using dev container like this (is not advice, but it is my way to run tests while using Windows):

FROM python:3.9.10
ENV PIP_DISABLE_ROOT_WARNING=1
RUN python -m pip install --upgrade pip
COPY requirements_test.txt requirements.txt
RUN pip install -r requirements.txt
VOLUME /app
WORKDIR /app
ENV NO_COLOR=yes_please
ENV LANG=C
CMD ["python", "-m", "pytest"]

and using project root as /app volume in the container.

fishy242 commented 1 year ago

Now I do coding and testing in WSL, I think that’s good enough for me at this moment.

Thanks all the help from here!

fredck commented 10 months ago

I'm stuck with this error as well... on MacOS though...

tests/components/lightener/test_config_flow.py Error attempting to connect to extension communication socket[vscode-pytest]: A test tried to use socket.socket.
If you are on a Windows machine, this error may be occurring if any of your tests clear environment variables as they are required to communicate with the extension. Please reference https://docs.pytest.org/en/stable/how-to/monkeypatch.html#monkeypatching-environment-variablesfor the correct way to clear environment variables during testing.
matthewturner commented 6 months ago

I have run into this issue with a DevContainer on Windows. The tests run from the CLI but fail in VS Code. The solution for me was to comment out the code which blocks sockets.

I've created a branch which you can test by replacing the pytest-homeassistant-custom-component requirement in your requirements file with:

pytest-homeassistant-custom-component @ git+https://github.com/matthewturner/pytest-homeassistant-custom-component@remove-socket-blocking

I'm not sure what the permanent solution to this would be.

Xyaren commented 4 months ago

Also happening within a remote dev-container running in docker on ubuntu.

Workaround for me is the following conftest.py class in my tests folder:

from pytest_socket import enable_socket, disable_socket, socket_allow_hosts
import pytest

@pytest.hookimpl(trylast=True)
def pytest_runtest_setup():
    enable_socket()
    socket_allow_hosts(["127.0.0.1", "localhost", "::1"], allow_unix_socket=True)

There is an update on the original issue from vscode: https://github.com/microsoft/vscode-python/issues/22383