1
0
mirror of https://github.com/home-assistant/core.git synced 2026-02-15 07:36:16 +00:00

Refactor GitHub tests to patch the library instead (#160568)

This commit is contained in:
Joost Lekkerkerker
2026-01-21 22:09:56 +01:00
committed by GitHub
parent b700a27c8f
commit bbe1d28e88
12 changed files with 286 additions and 373 deletions

View File

@@ -1 +1,13 @@
"""Tests for the GitHub integration."""
from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry
async def setup_integration(hass: HomeAssistant, config_entry: MockConfigEntry) -> None:
"""Method for setting up the component."""
config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()

View File

@@ -1,53 +0,0 @@
"""Common helpers for GitHub integration tests."""
from __future__ import annotations
import json
from homeassistant.components.github.const import CONF_REPOSITORIES, DOMAIN
from homeassistant.config_entries import ConfigEntryState
from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry, async_load_fixture
from tests.test_util.aiohttp import AiohttpClientMocker
MOCK_ACCESS_TOKEN = "gho_16C7e42F292c6912E7710c838347Ae178B4a"
TEST_REPOSITORY = "octocat/Hello-World"
async def setup_github_integration(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
aioclient_mock: AiohttpClientMocker,
add_entry_to_hass: bool = True,
) -> None:
"""Mock setting up the integration."""
headers = json.loads(await async_load_fixture(hass, "base_headers.json", DOMAIN))
for idx, repository in enumerate(mock_config_entry.options[CONF_REPOSITORIES]):
aioclient_mock.get(
f"https://api.github.com/repos/{repository}",
json={
**json.loads(await async_load_fixture(hass, "repository.json", DOMAIN)),
"full_name": repository,
"id": idx,
},
headers=headers,
)
aioclient_mock.get(
f"https://api.github.com/repos/{repository}/events",
json=[],
headers=headers,
)
aioclient_mock.post(
"https://api.github.com/graphql",
json=json.loads(await async_load_fixture(hass, "graphql.json", DOMAIN)),
headers=headers,
)
if add_entry_to_hass:
mock_config_entry.add_to_hass(hass)
setup_result = await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()
assert setup_result
assert mock_config_entry.state is ConfigEntryState.LOADED

View File

@@ -1,18 +1,27 @@
"""conftest for the GitHub integration."""
import asyncio
from collections.abc import Generator
from unittest.mock import patch
from unittest.mock import AsyncMock, MagicMock, patch
from aiogithubapi import (
GitHubLoginDeviceModel,
GitHubLoginOauthModel,
GitHubRateLimitModel,
)
import pytest
from homeassistant.components.github.const import CONF_REPOSITORIES, DOMAIN
from homeassistant.const import CONF_ACCESS_TOKEN
from homeassistant.core import HomeAssistant
from .common import MOCK_ACCESS_TOKEN, TEST_REPOSITORY, setup_github_integration
from .const import MOCK_ACCESS_TOKEN, TEST_REPOSITORY
from tests.common import MockConfigEntry
from tests.test_util.aiohttp import AiohttpClientMocker
from tests.common import (
MockConfigEntry,
async_load_json_object_fixture,
load_json_object_fixture,
)
@pytest.fixture
@@ -34,11 +43,93 @@ def mock_setup_entry() -> Generator[None]:
@pytest.fixture
async def init_integration(
def device_activation_event() -> asyncio.Event:
"""Fixture to provide an asyncio event for device activation."""
return asyncio.Event()
@pytest.fixture
def github_device_client(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
aioclient_mock: AiohttpClientMocker,
) -> MockConfigEntry:
"""Set up the GitHub integration for testing."""
await setup_github_integration(hass, mock_config_entry, aioclient_mock)
return mock_config_entry
device_activation_event: asyncio.Event,
) -> Generator[AsyncMock]:
"""Mock GitHub device client."""
with patch(
"homeassistant.components.github.config_flow.GitHubDeviceAPI",
autospec=True,
) as github_client_mock:
client = github_client_mock.return_value
register_object = AsyncMock()
register_object.data = GitHubLoginDeviceModel(
load_json_object_fixture("device_register.json", DOMAIN)
)
client.register.return_value = register_object
async def mock_api_device_activation(device_code) -> AsyncMock:
# Simulate the device activation process
await device_activation_event.wait()
activate_object = AsyncMock()
activate_object.data = GitHubLoginOauthModel(
await async_load_json_object_fixture(
hass, "device_activate.json", DOMAIN
)
)
return activate_object
client.activation = mock_api_device_activation
yield client
@pytest.fixture
def github_client(hass: HomeAssistant) -> Generator[AsyncMock]:
"""Mock GitHub device client."""
with (
patch(
"homeassistant.components.github.config_flow.GitHubAPI",
autospec=True,
) as github_client_mock,
patch("homeassistant.components.github.GitHubAPI", new=github_client_mock),
patch(
"homeassistant.components.github.diagnostics.GitHubAPI",
new=github_client_mock,
),
):
client = github_client_mock.return_value
client.user.starred = AsyncMock(
side_effect=[
MagicMock(
is_last_page=False,
next_page_number=2,
last_page_number=2,
data=[MagicMock(full_name="home-assistant/core")],
),
MagicMock(
is_last_page=True,
data=[MagicMock(full_name="home-assistant/frontend")],
),
]
)
client.user.repos = AsyncMock(
side_effect=[
MagicMock(
is_last_page=False,
next_page_number=2,
last_page_number=2,
data=[MagicMock(full_name="home-assistant/operating-system")],
),
MagicMock(
is_last_page=True,
data=[MagicMock(full_name="esphome/esphome")],
),
]
)
rate_limit_mock = AsyncMock()
rate_limit_mock.data = GitHubRateLimitModel(
load_json_object_fixture("rate_limit.json", DOMAIN)
)
client.rate_limit.return_value = rate_limit_mock
graphql_mock = AsyncMock()
graphql_mock.data = load_json_object_fixture("graphql.json", DOMAIN)
client.graphql.return_value = graphql_mock
client.repos.events.subscribe = AsyncMock()
yield client

View File

@@ -0,0 +1,4 @@
"""Constants for GitHub integration tests."""
MOCK_ACCESS_TOKEN = "gho_16C7e42F292c6912E7710c838347Ae178B4a"
TEST_REPOSITORY = "octocat/Hello-World"

View File

@@ -1,29 +0,0 @@
{
"Server": "GitHub.com",
"Date": "Mon, 1 Jan 1970 00:00:00 GMT",
"Content-Type": "application/json; charset=utf-8",
"Transfer-Encoding": "chunked",
"Cache-Control": "private, max-age=60, s-maxage=60",
"Vary": "Accept, Authorization, Cookie, X-GitHub-OTP",
"Etag": "W/\"1234567890abcdefghijklmnopqrstuvwxyz\"",
"X-OAuth-Scopes": "",
"X-Accepted-OAuth-Scopes": "",
"github-authentication-token-expiration": "1970-01-01 01:00:00 UTC",
"X-GitHub-Media-Type": "github.v3; param=raw; format=json",
"X-RateLimit-Limit": "5000",
"X-RateLimit-Remaining": "4999",
"X-RateLimit-Reset": "1",
"X-RateLimit-Used": "1",
"X-RateLimit-Resource": "core",
"Access-Control-Expose-Headers": "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, Deprecation, Sunset",
"Access-Control-Allow-Origin": "*",
"Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload",
"X-Frame-Options": "deny",
"X-Content-Type-Options": "nosniff",
"X-XSS-Protection": "0",
"Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin",
"Content-Security-Policy": "default-src 'none'",
"Content-Encoding": "gzip",
"Permissions-Policy": "",
"X-GitHub-Request-Id": "12A3:45BC:6D7890:12EF34:5678G901"
}

View File

@@ -0,0 +1,5 @@
{
"access_token": "gho_16C7e42F292c6912E7710c838347Ae178B4a",
"token_type": "bearer",
"scope": ""
}

View File

@@ -0,0 +1,7 @@
{
"device_code": "3584d83530557fdd1f46af8289938c8ef79f9dc5",
"user_code": "WDJB-MJHT",
"verification_uri": "https://github.com/login/device",
"expires_in": 900,
"interval": 5
}

View File

@@ -0,0 +1 @@
{ "resources": { "core": { "remaining": 100, "limit": 100 } } }

View File

@@ -1,146 +1,100 @@
"""Test the GitHub config flow."""
from unittest.mock import AsyncMock, MagicMock, patch
import asyncio
from unittest.mock import AsyncMock, MagicMock
from aiogithubapi import GitHubException
from freezegun.api import FrozenDateTimeFactory
import pytest
from homeassistant import config_entries
from homeassistant.components.github.config_flow import get_repositories
from homeassistant.components.github.const import (
CONF_REPOSITORIES,
DEFAULT_REPOSITORIES,
DOMAIN,
)
from homeassistant.config_entries import SOURCE_USER
from homeassistant.const import CONF_ACCESS_TOKEN
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType, UnknownFlow
from .common import MOCK_ACCESS_TOKEN
from .const import MOCK_ACCESS_TOKEN
from tests.common import MockConfigEntry
from tests.test_util.aiohttp import AiohttpClientMocker
async def test_full_user_flow_implementation(
hass: HomeAssistant,
mock_setup_entry: None,
aioclient_mock: AiohttpClientMocker,
freezer: FrozenDateTimeFactory,
github_device_client: AsyncMock,
github_client: AsyncMock,
device_activation_event: asyncio.Event,
) -> None:
"""Test the full manual user flow from start to finish."""
aioclient_mock.post(
"https://github.com/login/device/code",
json={
"device_code": "3584d83530557fdd1f46af8289938c8ef79f9dc5",
"user_code": "WDJB-MJHT",
"verification_uri": "https://github.com/login/device",
"expires_in": 900,
"interval": 5,
},
headers={"Content-Type": "application/json"},
)
# User has not yet entered the code
aioclient_mock.post(
"https://github.com/login/oauth/access_token",
json={"error": "authorization_pending"},
headers={"Content-Type": "application/json"},
)
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_USER},
DOMAIN, context={"source": SOURCE_USER}
)
assert result["step_id"] == "device"
assert result["type"] is FlowResultType.SHOW_PROGRESS
# User enters the code
aioclient_mock.clear_requests()
aioclient_mock.post(
"https://github.com/login/oauth/access_token",
json={
CONF_ACCESS_TOKEN: MOCK_ACCESS_TOKEN,
"token_type": "bearer",
"scope": "",
},
headers={"Content-Type": "application/json"},
)
freezer.tick(10)
device_activation_event.set()
await hass.async_block_till_done()
result = await hass.config_entries.flow.async_configure(result["flow_id"])
assert result["step_id"] == "repositories"
assert result["type"] is FlowResultType.FORM
assert not result["errors"]
schema = result["data_schema"]
repositories = schema.schema[CONF_REPOSITORIES].options
assert len(repositories) == 4
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={
CONF_REPOSITORIES: DEFAULT_REPOSITORIES,
},
result["flow_id"], user_input={CONF_REPOSITORIES: DEFAULT_REPOSITORIES}
)
assert result["title"] == ""
assert result["type"] is FlowResultType.CREATE_ENTRY
assert "data" in result
assert result["data"][CONF_ACCESS_TOKEN] == MOCK_ACCESS_TOKEN
assert "options" in result
assert result["options"][CONF_REPOSITORIES] == DEFAULT_REPOSITORIES
assert result["data"] == {CONF_ACCESS_TOKEN: MOCK_ACCESS_TOKEN}
assert result["options"] == {CONF_REPOSITORIES: DEFAULT_REPOSITORIES}
async def test_flow_with_registration_failure(
hass: HomeAssistant,
aioclient_mock: AiohttpClientMocker,
github_device_client: AsyncMock,
) -> None:
"""Test flow with registration failure of the device."""
aioclient_mock.post(
"https://github.com/login/device/code",
exc=GitHubException("Registration failed"),
)
github_device_client.register.side_effect = GitHubException("Registration failed")
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_USER},
DOMAIN, context={"source": SOURCE_USER}
)
assert result["type"] is FlowResultType.ABORT
assert result.get("reason") == "could_not_register"
assert result["reason"] == "could_not_register"
async def test_flow_with_activation_failure(
hass: HomeAssistant,
aioclient_mock: AiohttpClientMocker,
freezer: FrozenDateTimeFactory,
github_device_client: AsyncMock,
device_activation_event: asyncio.Event,
) -> None:
"""Test flow with activation failure of the device."""
aioclient_mock.post(
"https://github.com/login/device/code",
json={
"device_code": "3584d83530557fdd1f46af8289938c8ef79f9dc5",
"user_code": "WDJB-MJHT",
"verification_uri": "https://github.com/login/device",
"expires_in": 900,
"interval": 5,
},
headers={"Content-Type": "application/json"},
)
# User has not yet entered the code
aioclient_mock.post(
"https://github.com/login/oauth/access_token",
json={"error": "authorization_pending"},
headers={"Content-Type": "application/json"},
)
async def mock_api_device_activation(device_code) -> None:
# Simulate the device activation process
await device_activation_event.wait()
raise GitHubException("Activation failed")
github_device_client.activation = mock_api_device_activation
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_USER},
DOMAIN, context={"source": SOURCE_USER}
)
assert result["step_id"] == "device"
assert result["type"] is FlowResultType.SHOW_PROGRESS
# Activation fails
aioclient_mock.clear_requests()
aioclient_mock.post(
"https://github.com/login/oauth/access_token",
exc=GitHubException("Activation failed"),
)
freezer.tick(10)
device_activation_event.set()
await hass.async_block_till_done()
result = await hass.config_entries.flow.async_configure(result["flow_id"])
@@ -149,30 +103,14 @@ async def test_flow_with_activation_failure(
async def test_flow_with_remove_while_activating(
hass: HomeAssistant,
aioclient_mock: AiohttpClientMocker,
hass: HomeAssistant, github_device_client: AsyncMock
) -> None:
"""Test flow with user canceling while activating."""
aioclient_mock.post(
"https://github.com/login/device/code",
json={
"device_code": "3584d83530557fdd1f46af8289938c8ef79f9dc5",
"user_code": "WDJB-MJHT",
"verification_uri": "https://github.com/login/device",
"expires_in": 900,
"interval": 5,
},
headers={"Content-Type": "application/json"},
)
aioclient_mock.post(
"https://github.com/login/oauth/access_token",
json={"error": "authorization_pending"},
headers={"Content-Type": "application/json"},
)
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_USER},
DOMAIN, context={"source": SOURCE_USER}
)
assert result["step_id"] == "device"
assert result["type"] is FlowResultType.SHOW_PROGRESS
@@ -194,84 +132,88 @@ async def test_already_configured(
mock_config_entry.add_to_hass(hass)
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_USER},
DOMAIN, context={"source": SOURCE_USER}
)
assert result["type"] is FlowResultType.ABORT
assert result.get("reason") == "already_configured"
assert result["reason"] == "already_configured"
async def test_starred_pagination_with_paginated_result(hass: HomeAssistant) -> None:
"""Test pagination of starred repositories with paginated result."""
with patch(
"homeassistant.components.github.config_flow.GitHubAPI",
return_value=MagicMock(
user=MagicMock(
starred=AsyncMock(
return_value=MagicMock(
is_last_page=False,
next_page_number=2,
last_page_number=2,
data=[MagicMock(full_name="home-assistant/core")],
)
),
repos=AsyncMock(
return_value=MagicMock(
is_last_page=False,
next_page_number=2,
last_page_number=2,
data=[MagicMock(full_name="awesome/reposiotry")],
)
),
)
),
):
repos = await get_repositories(hass, MOCK_ACCESS_TOKEN)
async def test_no_repositories(
hass: HomeAssistant,
mock_setup_entry: None,
github_device_client: AsyncMock,
github_client: AsyncMock,
device_activation_event: asyncio.Event,
) -> None:
"""Test the full manual user flow from start to finish."""
assert len(repos) == 2
assert repos[-1] == DEFAULT_REPOSITORIES[0]
github_client.user.repos.side_effect = [MagicMock(is_last_page=True, data=[])]
github_client.user.starred.side_effect = [MagicMock(is_last_page=True, data=[])]
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
assert result["step_id"] == "device"
assert result["type"] is FlowResultType.SHOW_PROGRESS
device_activation_event.set()
await hass.async_block_till_done()
result = await hass.config_entries.flow.async_configure(result["flow_id"])
assert result["step_id"] == "repositories"
assert result["type"] is FlowResultType.FORM
assert not result["errors"]
schema = result["data_schema"]
repositories = schema.schema[CONF_REPOSITORIES].options
assert len(repositories) == 2
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={CONF_REPOSITORIES: DEFAULT_REPOSITORIES}
)
assert result["type"] is FlowResultType.CREATE_ENTRY
async def test_starred_pagination_with_no_starred(hass: HomeAssistant) -> None:
"""Test pagination of starred repositories with no starred."""
with patch(
"homeassistant.components.github.config_flow.GitHubAPI",
return_value=MagicMock(
user=MagicMock(
starred=AsyncMock(
return_value=MagicMock(
is_last_page=True,
data=[],
)
),
repos=AsyncMock(
return_value=MagicMock(
is_last_page=True,
data=[],
)
),
)
),
):
repos = await get_repositories(hass, MOCK_ACCESS_TOKEN)
async def test_exception_during_repository_fetch(
hass: HomeAssistant,
mock_setup_entry: None,
github_device_client: AsyncMock,
github_client: AsyncMock,
device_activation_event: asyncio.Event,
) -> None:
"""Test the full manual user flow from start to finish."""
assert len(repos) == 2
assert repos == DEFAULT_REPOSITORIES
github_client.user.repos.side_effect = GitHubException()
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
async def test_starred_pagination_with_exception(hass: HomeAssistant) -> None:
"""Test pagination of starred repositories with exception."""
with patch(
"homeassistant.components.github.config_flow.GitHubAPI",
return_value=MagicMock(
user=MagicMock(starred=AsyncMock(side_effect=GitHubException("Error")))
),
):
repos = await get_repositories(hass, MOCK_ACCESS_TOKEN)
assert result["step_id"] == "device"
assert result["type"] is FlowResultType.SHOW_PROGRESS
assert len(repos) == 2
assert repos == DEFAULT_REPOSITORIES
device_activation_event.set()
await hass.async_block_till_done()
result = await hass.config_entries.flow.async_configure(result["flow_id"])
assert result["step_id"] == "repositories"
assert result["type"] is FlowResultType.FORM
assert not result["errors"]
schema = result["data_schema"]
repositories = schema.schema[CONF_REPOSITORIES].options
assert len(repositories) == 2
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={CONF_REPOSITORIES: DEFAULT_REPOSITORIES}
)
assert result["type"] is FlowResultType.CREATE_ENTRY
async def test_options_flow(

View File

@@ -1,89 +1,56 @@
"""Test GitHub diagnostics."""
import json
from unittest.mock import AsyncMock
from aiogithubapi import GitHubException
import pytest
from homeassistant.components.github.const import CONF_REPOSITORIES, DOMAIN
from homeassistant.core import HomeAssistant
from .common import setup_github_integration
from . import setup_integration
from tests.common import MockConfigEntry, async_load_fixture
from tests.common import MockConfigEntry
from tests.components.diagnostics import get_diagnostics_for_config_entry
from tests.test_util.aiohttp import AiohttpClientMocker
from tests.typing import ClientSessionGenerator
# This tests needs to be adjusted to remove lingering tasks
@pytest.mark.parametrize("expected_lingering_tasks", [True])
async def test_entry_diagnostics(
hass: HomeAssistant,
hass_client: ClientSessionGenerator,
mock_config_entry: MockConfigEntry,
aioclient_mock: AiohttpClientMocker,
github_client: AsyncMock,
) -> None:
"""Test config entry diagnostics."""
mock_config_entry.add_to_hass(hass)
hass.config_entries.async_update_entry(
mock_config_entry,
options={CONF_REPOSITORIES: ["home-assistant/core"]},
)
response_json = json.loads(await async_load_fixture(hass, "graphql.json", DOMAIN))
response_json["data"]["repository"]["full_name"] = "home-assistant/core"
aioclient_mock.post(
"https://api.github.com/graphql",
json=response_json,
headers=json.loads(await async_load_fixture(hass, "base_headers.json", DOMAIN)),
)
aioclient_mock.get(
"https://api.github.com/rate_limit",
json={"resources": {"core": {"remaining": 100, "limit": 100}}},
headers={"Content-Type": "application/json"},
)
await setup_github_integration(
hass, mock_config_entry, aioclient_mock, add_entry_to_hass=False
)
await setup_integration(hass, mock_config_entry)
result = await get_diagnostics_for_config_entry(
hass,
hass_client,
mock_config_entry,
)
assert result["options"]["repositories"] == ["home-assistant/core"]
assert result["options"]["repositories"] == ["octocat/Hello-World"]
assert result["rate_limit"] == {
"resources": {"core": {"remaining": 100, "limit": 100}}
}
assert (
result["repositories"]["home-assistant/core"]["full_name"]
== "home-assistant/core"
result["repositories"]["octocat/Hello-World"]["full_name"]
== "octocat/Hello-World"
)
# This tests needs to be adjusted to remove lingering tasks
@pytest.mark.parametrize("expected_lingering_tasks", [True])
async def test_entry_diagnostics_exception(
hass: HomeAssistant,
hass_client: ClientSessionGenerator,
init_integration: MockConfigEntry,
aioclient_mock: AiohttpClientMocker,
mock_config_entry: MockConfigEntry,
github_client: AsyncMock,
) -> None:
"""Test config entry diagnostics with exception for ratelimit."""
aioclient_mock.get(
"https://api.github.com/rate_limit",
exc=GitHubException("error"),
)
await setup_integration(hass, mock_config_entry)
github_client.rate_limit.side_effect = GitHubException("error")
result = await get_diagnostics_for_config_entry(
hass,
hass_client,
init_integration,
mock_config_entry,
)
assert (
result["rate_limit"]["error"]
== "Unexpected exception for 'https://api.github.com/rate_limit' with - error"
)
assert result["rate_limit"]["error"] == "error"

View File

@@ -1,24 +1,23 @@
"""Test the GitHub init file."""
from unittest.mock import AsyncMock
import pytest
from homeassistant.components.github import CONF_REPOSITORIES
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, entity_registry as er, icon
from .common import setup_github_integration
from . import setup_integration
from tests.common import MockConfigEntry
from tests.test_util.aiohttp import AiohttpClientMocker
# This tests needs to be adjusted to remove lingering tasks
@pytest.mark.parametrize("expected_lingering_tasks", [True])
async def test_device_registry_cleanup(
hass: HomeAssistant,
device_registry: dr.DeviceRegistry,
mock_config_entry: MockConfigEntry,
aioclient_mock: AiohttpClientMocker,
github_client: AsyncMock,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test that we remove untracked repositories from the device registry."""
@@ -27,9 +26,7 @@ async def test_device_registry_cleanup(
mock_config_entry,
options={CONF_REPOSITORIES: ["home-assistant/core"]},
)
await setup_github_integration(
hass, mock_config_entry, aioclient_mock, add_entry_to_hass=False
)
await setup_integration(hass, mock_config_entry)
devices = dr.async_entries_for_config_entry(
registry=device_registry,
@@ -58,12 +55,10 @@ async def test_device_registry_cleanup(
assert len(devices) == 0
# This tests needs to be adjusted to remove lingering tasks
@pytest.mark.parametrize("expected_lingering_tasks", [True])
async def test_subscription_setup(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
aioclient_mock: AiohttpClientMocker,
github_client: AsyncMock,
) -> None:
"""Test that we setup event subscription."""
mock_config_entry.add_to_hass(hass)
@@ -72,21 +67,14 @@ async def test_subscription_setup(
options={CONF_REPOSITORIES: ["home-assistant/core"]},
pref_disable_polling=False,
)
await setup_github_integration(
hass, mock_config_entry, aioclient_mock, add_entry_to_hass=False
)
assert (
"https://api.github.com/repos/home-assistant/core/events" in x[1]
for x in aioclient_mock.mock_calls
)
await setup_integration(hass, mock_config_entry)
github_client.repos.events.subscribe.assert_called_once()
# This tests needs to be adjusted to remove lingering tasks
@pytest.mark.parametrize("expected_lingering_tasks", [True])
async def test_subscription_setup_polling_disabled(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
aioclient_mock: AiohttpClientMocker,
github_client: AsyncMock,
) -> None:
"""Test that we do not setup event subscription if polling is disabled."""
mock_config_entry.add_to_hass(hass)
@@ -95,13 +83,8 @@ async def test_subscription_setup_polling_disabled(
options={CONF_REPOSITORIES: ["home-assistant/core"]},
pref_disable_polling=True,
)
await setup_github_integration(
hass, mock_config_entry, aioclient_mock, add_entry_to_hass=False
)
assert (
"https://api.github.com/repos/home-assistant/core/events" not in x[1]
for x in aioclient_mock.mock_calls
)
await setup_integration(hass, mock_config_entry)
github_client.repos.events.subscribe.assert_not_called()
# Prove that we subscribed if the user enabled polling again
hass.config_entries.async_update_entry(
@@ -109,23 +92,20 @@ async def test_subscription_setup_polling_disabled(
)
assert await hass.config_entries.async_reload(mock_config_entry.entry_id)
await hass.async_block_till_done()
assert (
"https://api.github.com/repos/home-assistant/core/events" in x[1]
for x in aioclient_mock.mock_calls
)
github_client.repos.events.subscribe.assert_called_once()
# This tests needs to be adjusted to remove lingering tasks
@pytest.mark.parametrize("expected_lingering_tasks", [True])
async def test_sensor_icons(
hass: HomeAssistant,
init_integration: MockConfigEntry,
github_client: AsyncMock,
mock_config_entry: MockConfigEntry,
entity_registry: er.EntityRegistry,
) -> None:
"""Test to ensure that all sensor entities have an icon definition."""
await setup_integration(hass, mock_config_entry)
entities = er.async_entries_for_config_entry(
entity_registry,
config_entry_id=init_integration.entry_id,
config_entry_id=mock_config_entry.entry_id,
)
icons = await icon.async_get_icons(hass, "entity", integrations=["github"])

View File

@@ -1,50 +1,36 @@
"""Test GitHub sensor."""
import json
from unittest.mock import AsyncMock
import pytest
from freezegun.api import FrozenDateTimeFactory
from homeassistant.components.github.const import DOMAIN, FALLBACK_UPDATE_INTERVAL
from homeassistant.components.github.const import FALLBACK_UPDATE_INTERVAL
from homeassistant.const import STATE_UNAVAILABLE
from homeassistant.core import HomeAssistant
from homeassistant.util import dt as dt_util
from .common import TEST_REPOSITORY
from . import setup_integration
from tests.common import MockConfigEntry, async_fire_time_changed, async_load_fixture
from tests.test_util.aiohttp import AiohttpClientMocker
from tests.common import MockConfigEntry, async_fire_time_changed
TEST_SENSOR_ENTITY = "sensor.octocat_hello_world_latest_release"
# This tests needs to be adjusted to remove lingering tasks
@pytest.mark.parametrize("expected_lingering_tasks", [True])
async def test_sensor_updates_with_empty_release_array(
hass: HomeAssistant,
init_integration: MockConfigEntry,
aioclient_mock: AiohttpClientMocker,
github_client: AsyncMock,
mock_config_entry: MockConfigEntry,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test the sensor updates by default GitHub sensors."""
await setup_integration(hass, mock_config_entry)
state = hass.states.get(TEST_SENSOR_ENTITY)
assert state.state == "v1.0.0"
response_json = json.loads(await async_load_fixture(hass, "graphql.json", DOMAIN))
response_json["data"]["repository"]["release"] = None
headers = json.loads(await async_load_fixture(hass, "base_headers.json", DOMAIN))
github_client.graphql.return_value.data["data"]["repository"]["release"] = None
aioclient_mock.clear_requests()
aioclient_mock.get(
f"https://api.github.com/repos/{TEST_REPOSITORY}/events",
json=[],
headers=headers,
)
aioclient_mock.post(
"https://api.github.com/graphql",
json=response_json,
headers=headers,
)
async_fire_time_changed(hass, dt_util.utcnow() + FALLBACK_UPDATE_INTERVAL)
freezer.tick(FALLBACK_UPDATE_INTERVAL)
async_fire_time_changed(hass)
await hass.async_block_till_done()
new_state = hass.states.get(TEST_SENSOR_ENTITY)
assert new_state.state == "unavailable"
assert new_state.state == STATE_UNAVAILABLE