From 93ff3591cb1f149c63bbd794a0cf5cf6c34a5a95 Mon Sep 17 00:00:00 2001 From: MatthewFlamm <39341281+MatthewFlamm@users.noreply.github.com> Date: Wed, 27 Oct 2021 20:19:48 -0400 Subject: [PATCH] [create-pull-request] automated change (#86) Co-authored-by: MatthewFlamm --- README.md | 2 +- .../const.py | 4 +- .../ignore_uncaught_exceptions.py | 6 ++ .../plugins.py | 72 ++++++++++++++++++- .../test_util/aiohttp.py | 5 +- requirements_test.txt | 5 +- 6 files changed, 84 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 211ab35..88fbd44 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # pytest-homeassistant-custom-component -![HA core version](https://img.shields.io/static/v1?label=HA+core+version&message=2021.10.0b1&labelColor=blue) +![HA core version](https://img.shields.io/static/v1?label=HA+core+version&message=2021.11.0b0&labelColor=blue) Package to automatically extract testing plugins from Home Assistant for custom component testing. The goal is to provide the same functionality as the tests in home-assistant/core. diff --git a/pytest_homeassistant_custom_component/const.py b/pytest_homeassistant_custom_component/const.py index f73ddf5..584d7b5 100644 --- a/pytest_homeassistant_custom_component/const.py +++ b/pytest_homeassistant_custom_component/const.py @@ -8,7 +8,7 @@ from typing import Final MAJOR_VERSION: Final = 2021 -MINOR_VERSION: Final = 10 -PATCH_VERSION: Final = "0b1" +MINOR_VERSION: Final = 11 +PATCH_VERSION: Final = "0b0" __short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__: Final = f"{__short_version__}.{PATCH_VERSION}" diff --git a/pytest_homeassistant_custom_component/ignore_uncaught_exceptions.py b/pytest_homeassistant_custom_component/ignore_uncaught_exceptions.py index 9f21893..871c560 100644 --- a/pytest_homeassistant_custom_component/ignore_uncaught_exceptions.py +++ b/pytest_homeassistant_custom_component/ignore_uncaught_exceptions.py @@ -4,6 +4,12 @@ This file is originally from homeassistant/core and modified by pytest-homeassistant-custom-component. """ IGNORE_UNCAUGHT_EXCEPTIONS = [ + ( + # This test explicitly throws an uncaught exception + # and should not be removed. + ".test_runner", + "test_unhandled_exception_traceback", + ), ( "test_homeassistant_bridge", "test_homeassistant_bridge_fan_setup", diff --git a/pytest_homeassistant_custom_component/plugins.py b/pytest_homeassistant_custom_component/plugins.py index 7af8e37..4afbb21 100644 --- a/pytest_homeassistant_custom_component/plugins.py +++ b/pytest_homeassistant_custom_component/plugins.py @@ -7,6 +7,7 @@ import datetime import functools import logging +import socket import ssl import threading from unittest.mock import MagicMock, patch @@ -14,6 +15,7 @@ from aiohttp.test_utils import make_mocked_request import multidict import pytest +import pytest_socket import requests_mock as _requests_mock from homeassistant import core as ha, loader, runner, util @@ -65,6 +67,70 @@ def pytest_configure(config): ) +def pytest_runtest_setup(): + """Throw if tests attempt to open sockets. + + allow_unix_socket is set to True because it's needed by asyncio. + Important: socket_allow_hosts must be called before disable_socket, otherwise all + destinations will be allowed. + """ + pytest_socket.socket_allow_hosts(["127.0.0.1"]) + disable_socket(allow_unix_socket=True) + + +@pytest.fixture +def socket_disabled(pytestconfig): + """Disable socket.socket for duration of this test function. + + This incorporates changes from https://github.com/miketheman/pytest-socket/pull/76 + and hardcodes allow_unix_socket to True because it's not passed on the command line. + """ + socket_was_enabled = socket.socket == pytest_socket._true_socket + disable_socket(allow_unix_socket=True) + yield + if socket_was_enabled: + pytest_socket.enable_socket() + + +@pytest.fixture +def socket_enabled(pytestconfig): + """Enable socket.socket for duration of this test function. + + This incorporates changes from https://github.com/miketheman/pytest-socket/pull/76 + and hardcodes allow_unix_socket to True because it's not passed on the command line. + """ + socket_was_disabled = socket.socket != pytest_socket._true_socket + pytest_socket.enable_socket() + yield + if socket_was_disabled: + disable_socket(allow_unix_socket=True) + + +def disable_socket(allow_unix_socket=False): + """Disable socket.socket to disable the Internet. useful in testing. + + This incorporates changes from https://github.com/miketheman/pytest-socket/pull/75 + """ + + class GuardedSocket(socket.socket): + """socket guard to disable socket creation (from pytest-socket).""" + + def __new__(cls, *args, **kwargs): + try: + if len(args) > 0: + is_unix_socket = args[0] == socket.AF_UNIX + else: + is_unix_socket = kwargs.get("family") == socket.AF_UNIX + except AttributeError: + # AF_UNIX not supported on Windows https://bugs.python.org/issue33408 + is_unix_socket = False + if is_unix_socket and allow_unix_socket: + return super().__new__(cls, *args, **kwargs) + raise pytest_socket.SocketBlockedError() + + socket.socket = GuardedSocket + + def check_real(func): """Force a function to require a keyword _test_real to be passed in.""" @@ -323,7 +389,7 @@ def local_auth(hass): @pytest.fixture -def hass_client(hass, aiohttp_client, hass_access_token): +def hass_client(hass, aiohttp_client, hass_access_token, socket_enabled): """Return an authenticated HTTP client.""" async def auth_client(): @@ -336,7 +402,7 @@ async def auth_client(): @pytest.fixture -def hass_client_no_auth(hass, aiohttp_client): +def hass_client_no_auth(hass, aiohttp_client, socket_enabled): """Return an unauthenticated HTTP client.""" async def client(): @@ -371,7 +437,7 @@ def current_request_with_host(current_request): @pytest.fixture -def hass_ws_client(aiohttp_client, hass_access_token, hass): +def hass_ws_client(aiohttp_client, hass_access_token, hass, socket_enabled): """Websocket client fixture connected to websocket server.""" async def create_client(hass=hass, access_token=hass_access_token): diff --git a/pytest_homeassistant_custom_component/test_util/aiohttp.py b/pytest_homeassistant_custom_component/test_util/aiohttp.py index edf8201..ca5e2df 100644 --- a/pytest_homeassistant_custom_component/test_util/aiohttp.py +++ b/pytest_homeassistant_custom_component/test_util/aiohttp.py @@ -5,6 +5,7 @@ """ import asyncio from contextlib import contextmanager +from http import HTTPStatus import json as _json import re from unittest import mock @@ -45,7 +46,7 @@ def request( url, *, auth=None, - status=200, + status=HTTPStatus.OK, text=None, data=None, content=None, @@ -161,7 +162,7 @@ def __init__( self, method, url, - status=200, + status=HTTPStatus.OK, response=None, json=None, text=None, diff --git a/requirements_test.txt b/requirements_test.txt index 2fae435..29152d3 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -8,13 +8,14 @@ -c homeassistant/package_constraints.txt -r requirements_test_pre_commit.txt -coverage==5.5 +coverage==6.0.2 jsonpickle==1.4.1 mock-open==1.4.0 pipdeptree==2.1.0 pylint-strict-informational==0.1 pytest-aiohttp==0.3.0 pytest-cov==2.12.1 +pytest-socket==0.4.1 pytest-test-groups==1.0.3 pytest-sugar==0.9.4 pytest-timeout==1.4.2 @@ -25,6 +26,6 @@ responses==0.12.0 respx==0.17.0 stdlib-list==0.7.0 tqdm==4.49.0 -homeassistant==2021.10.0b1 +homeassistant==2021.11.0b0 sqlalchemy==1.4.23