mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 21:27:38 +00:00
Add support for Minecraft SRV records (#32372)
* Added support for Minecraft SRV records * Switched from dnspython to aiodns, improved server ping and log messages, use address instead of host and port in config flow * Updated component requirements
This commit is contained in:
parent
cd57b764ce
commit
45241e57ca
@ -425,6 +425,7 @@ omit =
|
||||
homeassistant/components/minecraft_server/__init__.py
|
||||
homeassistant/components/minecraft_server/binary_sensor.py
|
||||
homeassistant/components/minecraft_server/const.py
|
||||
homeassistant/components/minecraft_server/helpers.py
|
||||
homeassistant/components/minecraft_server/sensor.py
|
||||
homeassistant/components/minio/*
|
||||
homeassistant/components/mitemp_bt/sensor.py
|
||||
|
@ -18,6 +18,7 @@ from homeassistant.helpers.entity import Entity
|
||||
from homeassistant.helpers.event import async_track_time_interval
|
||||
from homeassistant.helpers.typing import ConfigType, HomeAssistantType
|
||||
|
||||
from . import helpers
|
||||
from .const import DOMAIN, MANUFACTURER, SCAN_INTERVAL, SIGNAL_NAME_PREFIX
|
||||
|
||||
PLATFORMS = ["binary_sensor", "sensor"]
|
||||
@ -37,10 +38,9 @@ async def async_setup_entry(hass: HomeAssistantType, config_entry: ConfigEntry)
|
||||
# Create and store server instance.
|
||||
unique_id = config_entry.unique_id
|
||||
_LOGGER.debug(
|
||||
"Creating server instance for '%s' (host='%s', port=%s)",
|
||||
"Creating server instance for '%s' (%s)",
|
||||
config_entry.data[CONF_NAME],
|
||||
config_entry.data[CONF_HOST],
|
||||
config_entry.data[CONF_PORT],
|
||||
)
|
||||
server = MinecraftServer(hass, unique_id, config_entry.data)
|
||||
domain_data[unique_id] = server
|
||||
@ -82,7 +82,6 @@ class MinecraftServer:
|
||||
"""Representation of a Minecraft server."""
|
||||
|
||||
# Private constants
|
||||
_MAX_RETRIES_PING = 3
|
||||
_MAX_RETRIES_STATUS = 3
|
||||
|
||||
def __init__(
|
||||
@ -98,6 +97,7 @@ class MinecraftServer:
|
||||
self.port = config_data[CONF_PORT]
|
||||
self.online = False
|
||||
self._last_status_request_failed = False
|
||||
self.srv_record_checked = False
|
||||
|
||||
# 3rd party library instance
|
||||
self._mc_status = MCStatus(self.host, self.port)
|
||||
@ -127,15 +127,36 @@ class MinecraftServer:
|
||||
self._stop_periodic_update()
|
||||
|
||||
async def async_check_connection(self) -> None:
|
||||
"""Check server connection using a 'ping' request and store result."""
|
||||
"""Check server connection using a 'status' request and store connection status."""
|
||||
# Check if host is a valid SRV record, if not already done.
|
||||
if not self.srv_record_checked:
|
||||
self.srv_record_checked = True
|
||||
srv_record = await helpers.async_check_srv_record(self._hass, self.host)
|
||||
if srv_record is not None:
|
||||
_LOGGER.debug(
|
||||
"'%s' is a valid Minecraft SRV record ('%s:%s')",
|
||||
self.host,
|
||||
srv_record[CONF_HOST],
|
||||
srv_record[CONF_PORT],
|
||||
)
|
||||
# Overwrite host, port and 3rd party library instance
|
||||
# with data extracted out of SRV record.
|
||||
self.host = srv_record[CONF_HOST]
|
||||
self.port = srv_record[CONF_PORT]
|
||||
self._mc_status = MCStatus(self.host, self.port)
|
||||
|
||||
# Ping the server with a status request.
|
||||
try:
|
||||
await self._hass.async_add_executor_job(
|
||||
self._mc_status.ping, self._MAX_RETRIES_PING
|
||||
self._mc_status.status, self._MAX_RETRIES_STATUS
|
||||
)
|
||||
self.online = True
|
||||
except OSError as error:
|
||||
_LOGGER.debug(
|
||||
"Error occurred while trying to ping the server - OSError: %s", error
|
||||
"Error occurred while trying to check the connection to '%s:%s' - OSError: %s",
|
||||
self.host,
|
||||
self.port,
|
||||
error,
|
||||
)
|
||||
self.online = False
|
||||
|
||||
@ -148,9 +169,9 @@ class MinecraftServer:
|
||||
|
||||
# Inform user once about connection state changes if necessary.
|
||||
if server_online_old and not server_online:
|
||||
_LOGGER.warning("Connection to server lost")
|
||||
_LOGGER.warning("Connection to '%s:%s' lost", self.host, self.port)
|
||||
elif not server_online_old and server_online:
|
||||
_LOGGER.info("Connection to server (re-)established")
|
||||
_LOGGER.info("Connection to '%s:%s' (re-)established", self.host, self.port)
|
||||
|
||||
# Update the server properties if server is online.
|
||||
if server_online:
|
||||
@ -179,7 +200,11 @@ class MinecraftServer:
|
||||
|
||||
# Inform user once about successful update if necessary.
|
||||
if self._last_status_request_failed:
|
||||
_LOGGER.info("Updating the server properties succeeded again")
|
||||
_LOGGER.info(
|
||||
"Updating the properties of '%s:%s' succeeded again",
|
||||
self.host,
|
||||
self.port,
|
||||
)
|
||||
self._last_status_request_failed = False
|
||||
except OSError as error:
|
||||
# No answer to request, set all properties to unknown.
|
||||
@ -193,7 +218,10 @@ class MinecraftServer:
|
||||
# Inform user once about failed update if necessary.
|
||||
if not self._last_status_request_failed:
|
||||
_LOGGER.warning(
|
||||
"Updating the server properties failed - OSError: %s", error,
|
||||
"Updating the properties of '%s:%s' failed - OSError: %s",
|
||||
self.host,
|
||||
self.port,
|
||||
error,
|
||||
)
|
||||
self._last_status_request_failed = True
|
||||
|
||||
|
@ -9,7 +9,7 @@ from homeassistant import config_entries
|
||||
from homeassistant.config_entries import ConfigFlow
|
||||
from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PORT
|
||||
|
||||
from . import MinecraftServer
|
||||
from . import MinecraftServer, helpers
|
||||
from .const import ( # pylint: disable=unused-import
|
||||
DEFAULT_HOST,
|
||||
DEFAULT_NAME,
|
||||
@ -29,11 +29,24 @@ class MinecraftServerConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
errors = {}
|
||||
|
||||
if user_input is not None:
|
||||
# User inputs.
|
||||
host = user_input[CONF_HOST]
|
||||
port = user_input[CONF_PORT]
|
||||
host = None
|
||||
port = DEFAULT_PORT
|
||||
# Split address at last occurrence of ':'.
|
||||
address_left, separator, address_right = user_input[CONF_HOST].rpartition(
|
||||
":"
|
||||
)
|
||||
# If no separator is found, 'rpartition' return ('', '', original_string).
|
||||
if separator == "":
|
||||
host = address_right
|
||||
else:
|
||||
host = address_left
|
||||
try:
|
||||
port = int(address_right)
|
||||
except ValueError:
|
||||
pass # 'port' is already set to default value.
|
||||
|
||||
unique_id = ""
|
||||
# Remove '[' and ']' in case of an IPv6 address.
|
||||
host = host.strip("[]")
|
||||
|
||||
# Check if 'host' is a valid IP address and if so, get the MAC address.
|
||||
ip_address = None
|
||||
@ -42,6 +55,7 @@ class MinecraftServerConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
ip_address = ipaddress.ip_address(host)
|
||||
except ValueError:
|
||||
# Host is not a valid IP address.
|
||||
# Continue with host and port.
|
||||
pass
|
||||
else:
|
||||
# Host is a valid IP address.
|
||||
@ -55,38 +69,56 @@ class MinecraftServerConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
partial(getmac.get_mac_address, **params)
|
||||
)
|
||||
|
||||
# Validate IP address via valid MAC address.
|
||||
# Validate IP address (MAC address must be available).
|
||||
if ip_address is not None and mac_address is None:
|
||||
errors["base"] = "invalid_ip"
|
||||
# Validate port configuration (limit to user and dynamic port range).
|
||||
elif (port < 1024) or (port > 65535):
|
||||
errors["base"] = "invalid_port"
|
||||
# Validate host and port via ping request to server.
|
||||
# Validate host and port by checking the server connection.
|
||||
else:
|
||||
# Build unique_id.
|
||||
if ip_address is not None:
|
||||
# Since IP addresses can change and therefore are not allowed in a
|
||||
# unique_id, fall back to the MAC address.
|
||||
unique_id = f"{mac_address}-{port}"
|
||||
else:
|
||||
# Use host name in unique_id (host names should not change).
|
||||
unique_id = f"{host}-{port}"
|
||||
|
||||
# Abort in case the host was already configured before.
|
||||
await self.async_set_unique_id(unique_id)
|
||||
self._abort_if_unique_id_configured()
|
||||
|
||||
# Create server instance with configuration data and try pinging the server.
|
||||
server = MinecraftServer(self.hass, unique_id, user_input)
|
||||
# Create server instance with configuration data and ping the server.
|
||||
config_data = {
|
||||
CONF_NAME: user_input[CONF_NAME],
|
||||
CONF_HOST: host,
|
||||
CONF_PORT: port,
|
||||
}
|
||||
server = MinecraftServer(self.hass, "dummy_unique_id", config_data)
|
||||
await server.async_check_connection()
|
||||
if not server.online:
|
||||
# Host or port invalid or server not reachable.
|
||||
errors["base"] = "cannot_connect"
|
||||
else:
|
||||
# Build unique_id and config entry title.
|
||||
unique_id = ""
|
||||
title = f"{host}:{port}"
|
||||
if ip_address is not None:
|
||||
# Since IP addresses can change and therefore are not allowed in a
|
||||
# unique_id, fall back to the MAC address and port (to support
|
||||
# servers with same MAC address but different ports).
|
||||
unique_id = f"{mac_address}-{port}"
|
||||
if ip_address.version == 6:
|
||||
title = f"[{host}]:{port}"
|
||||
else:
|
||||
# Check if 'host' is a valid SRV record.
|
||||
srv_record = await helpers.async_check_srv_record(
|
||||
self.hass, host
|
||||
)
|
||||
if srv_record is not None:
|
||||
# Use only SRV host name in unique_id (does not change).
|
||||
unique_id = f"{host}-srv"
|
||||
title = host
|
||||
else:
|
||||
# Use host name and port in unique_id (to support servers with
|
||||
# same host name but different ports).
|
||||
unique_id = f"{host}-{port}"
|
||||
|
||||
# Abort in case the host was already configured before.
|
||||
await self.async_set_unique_id(unique_id)
|
||||
self._abort_if_unique_id_configured()
|
||||
|
||||
# Configuration data are available and no error was detected, create configuration entry.
|
||||
return self.async_create_entry(
|
||||
title=f"{host}:{port}", data=user_input
|
||||
)
|
||||
return self.async_create_entry(title=title, data=config_data)
|
||||
|
||||
# Show configuration form (default form in case of no user_input,
|
||||
# form filled with user_input and eventually with errors otherwise).
|
||||
@ -107,9 +139,6 @@ class MinecraftServerConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
vol.Required(
|
||||
CONF_HOST, default=user_input.get(CONF_HOST, DEFAULT_HOST)
|
||||
): vol.All(str, vol.Lower),
|
||||
vol.Optional(
|
||||
CONF_PORT, default=user_input.get(CONF_PORT, DEFAULT_PORT)
|
||||
): int,
|
||||
}
|
||||
),
|
||||
errors=errors,
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
ATTR_PLAYERS_LIST = "players_list"
|
||||
|
||||
DEFAULT_HOST = "localhost"
|
||||
DEFAULT_HOST = "localhost:25565"
|
||||
DEFAULT_NAME = "Minecraft Server"
|
||||
DEFAULT_PORT = 25565
|
||||
|
||||
@ -30,6 +30,8 @@ SCAN_INTERVAL = 60
|
||||
|
||||
SIGNAL_NAME_PREFIX = f"signal_{DOMAIN}"
|
||||
|
||||
SRV_RECORD_PREFIX = "_minecraft._tcp"
|
||||
|
||||
UNIT_PLAYERS_MAX = "players"
|
||||
UNIT_PLAYERS_ONLINE = "players"
|
||||
UNIT_PROTOCOL_VERSION = None
|
||||
|
32
homeassistant/components/minecraft_server/helpers.py
Normal file
32
homeassistant/components/minecraft_server/helpers.py
Normal file
@ -0,0 +1,32 @@
|
||||
"""Helper functions for the Minecraft Server integration."""
|
||||
|
||||
from typing import Any, Dict
|
||||
|
||||
import aiodns
|
||||
|
||||
from homeassistant.const import CONF_HOST, CONF_PORT
|
||||
from homeassistant.helpers.typing import HomeAssistantType
|
||||
|
||||
from .const import SRV_RECORD_PREFIX
|
||||
|
||||
|
||||
async def async_check_srv_record(hass: HomeAssistantType, host: str) -> Dict[str, Any]:
|
||||
"""Check if the given host is a valid Minecraft SRV record."""
|
||||
# Check if 'host' is a valid SRV record.
|
||||
return_value = None
|
||||
srv_records = None
|
||||
try:
|
||||
srv_records = await aiodns.DNSResolver().query(
|
||||
host=f"{SRV_RECORD_PREFIX}.{host}", qtype="SRV"
|
||||
)
|
||||
except (aiodns.error.DNSError):
|
||||
# 'host' is not a SRV record.
|
||||
pass
|
||||
else:
|
||||
# 'host' is a valid SRV record, extract the data.
|
||||
return_value = {
|
||||
CONF_HOST: srv_records[0].host,
|
||||
CONF_PORT: srv_records[0].port,
|
||||
}
|
||||
|
||||
return return_value
|
@ -3,7 +3,7 @@
|
||||
"name": "Minecraft Server",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/minecraft_server",
|
||||
"requirements": ["getmac==0.8.1", "mcstatus==2.3.0"],
|
||||
"requirements": ["aiodns==2.0.0", "getmac==0.8.1", "mcstatus==2.3.0"],
|
||||
"dependencies": [],
|
||||
"codeowners": ["@elmurato"],
|
||||
"quality_scale": "silver"
|
||||
|
@ -7,8 +7,7 @@
|
||||
"description": "Set up your Minecraft Server instance to allow monitoring.",
|
||||
"data": {
|
||||
"name": "Name",
|
||||
"host": "Host",
|
||||
"port": "Port"
|
||||
"host": "Host"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -152,6 +152,7 @@ aioautomatic==0.6.5
|
||||
aiobotocore==0.11.1
|
||||
|
||||
# homeassistant.components.dnsip
|
||||
# homeassistant.components.minecraft_server
|
||||
aiodns==2.0.0
|
||||
|
||||
# homeassistant.components.esphome
|
||||
|
@ -58,6 +58,10 @@ aioautomatic==0.6.5
|
||||
# homeassistant.components.aws
|
||||
aiobotocore==0.11.1
|
||||
|
||||
# homeassistant.components.dnsip
|
||||
# homeassistant.components.minecraft_server
|
||||
aiodns==2.0.0
|
||||
|
||||
# homeassistant.components.esphome
|
||||
aioesphomeapi==2.6.1
|
||||
|
||||
|
@ -1,5 +1,8 @@
|
||||
"""Test the Minecraft Server config flow."""
|
||||
|
||||
import asyncio
|
||||
|
||||
import aiodns
|
||||
from asynctest import patch
|
||||
from mcstatus.pinger import PingResponse
|
||||
|
||||
@ -19,6 +22,19 @@ from homeassistant.helpers.typing import HomeAssistantType
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
class QueryMock:
|
||||
"""Mock for result of aiodns.DNSResolver.query."""
|
||||
|
||||
def __init__(self):
|
||||
"""Set up query result mock."""
|
||||
self.host = "mc.dummyserver.com"
|
||||
self.port = 23456
|
||||
self.priority = 1
|
||||
self.weight = 1
|
||||
self.ttl = None
|
||||
|
||||
|
||||
STATUS_RESPONSE_RAW = {
|
||||
"description": {"text": "Dummy Description"},
|
||||
"version": {"name": "Dummy Version", "protocol": 123},
|
||||
@ -35,34 +51,34 @@ STATUS_RESPONSE_RAW = {
|
||||
|
||||
USER_INPUT = {
|
||||
CONF_NAME: DEFAULT_NAME,
|
||||
CONF_HOST: "mc.dummyserver.com",
|
||||
CONF_PORT: DEFAULT_PORT,
|
||||
CONF_HOST: f"mc.dummyserver.com:{DEFAULT_PORT}",
|
||||
}
|
||||
|
||||
USER_INPUT_SRV = {CONF_NAME: DEFAULT_NAME, CONF_HOST: "dummyserver.com"}
|
||||
|
||||
USER_INPUT_IPV4 = {
|
||||
CONF_NAME: DEFAULT_NAME,
|
||||
CONF_HOST: "1.1.1.1",
|
||||
CONF_PORT: DEFAULT_PORT,
|
||||
CONF_HOST: f"1.1.1.1:{DEFAULT_PORT}",
|
||||
}
|
||||
|
||||
USER_INPUT_IPV6 = {
|
||||
CONF_NAME: DEFAULT_NAME,
|
||||
CONF_HOST: "::ffff:0101:0101",
|
||||
CONF_PORT: DEFAULT_PORT,
|
||||
CONF_HOST: f"[::ffff:0101:0101]:{DEFAULT_PORT}",
|
||||
}
|
||||
|
||||
USER_INPUT_PORT_TOO_SMALL = {
|
||||
CONF_NAME: DEFAULT_NAME,
|
||||
CONF_HOST: "mc.dummyserver.com",
|
||||
CONF_PORT: 1023,
|
||||
CONF_HOST: f"mc.dummyserver.com:1023",
|
||||
}
|
||||
|
||||
USER_INPUT_PORT_TOO_LARGE = {
|
||||
CONF_NAME: DEFAULT_NAME,
|
||||
CONF_HOST: "mc.dummyserver.com",
|
||||
CONF_PORT: 65536,
|
||||
CONF_HOST: f"mc.dummyserver.com:65536",
|
||||
}
|
||||
|
||||
SRV_RECORDS = asyncio.Future()
|
||||
SRV_RECORDS.set_result([QueryMock()])
|
||||
|
||||
|
||||
async def test_show_config_form(hass: HomeAssistantType) -> None:
|
||||
"""Test if initial configuration form is shown."""
|
||||
@ -87,54 +103,96 @@ async def test_invalid_ip(hass: HomeAssistantType) -> None:
|
||||
|
||||
async def test_same_host(hass: HomeAssistantType) -> None:
|
||||
"""Test abort in case of same host name."""
|
||||
unique_id = f"{USER_INPUT[CONF_HOST]}-{USER_INPUT[CONF_PORT]}"
|
||||
mock_config_entry = MockConfigEntry(
|
||||
domain=DOMAIN, unique_id=unique_id, data=USER_INPUT
|
||||
)
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
with patch(
|
||||
"aiodns.DNSResolver.query", side_effect=aiodns.error.DNSError,
|
||||
):
|
||||
with patch(
|
||||
"mcstatus.server.MinecraftServer.status",
|
||||
return_value=PingResponse(STATUS_RESPONSE_RAW),
|
||||
):
|
||||
unique_id = "mc.dummyserver.com-25565"
|
||||
config_data = {
|
||||
CONF_NAME: DEFAULT_NAME,
|
||||
CONF_HOST: "mc.dummyserver.com",
|
||||
CONF_PORT: DEFAULT_PORT,
|
||||
}
|
||||
mock_config_entry = MockConfigEntry(
|
||||
domain=DOMAIN, unique_id=unique_id, data=config_data
|
||||
)
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": SOURCE_USER}, data=USER_INPUT
|
||||
)
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": SOURCE_USER}, data=USER_INPUT
|
||||
)
|
||||
|
||||
assert result["type"] == RESULT_TYPE_ABORT
|
||||
assert result["reason"] == "already_configured"
|
||||
assert result["type"] == RESULT_TYPE_ABORT
|
||||
assert result["reason"] == "already_configured"
|
||||
|
||||
|
||||
async def test_port_too_small(hass: HomeAssistantType) -> None:
|
||||
"""Test error in case of a too small port."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": SOURCE_USER}, data=USER_INPUT_PORT_TOO_SMALL
|
||||
)
|
||||
with patch(
|
||||
"aiodns.DNSResolver.query", side_effect=aiodns.error.DNSError,
|
||||
):
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": SOURCE_USER}, data=USER_INPUT_PORT_TOO_SMALL
|
||||
)
|
||||
|
||||
assert result["type"] == RESULT_TYPE_FORM
|
||||
assert result["errors"] == {"base": "invalid_port"}
|
||||
assert result["type"] == RESULT_TYPE_FORM
|
||||
assert result["errors"] == {"base": "invalid_port"}
|
||||
|
||||
|
||||
async def test_port_too_large(hass: HomeAssistantType) -> None:
|
||||
"""Test error in case of a too large port."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": SOURCE_USER}, data=USER_INPUT_PORT_TOO_LARGE
|
||||
)
|
||||
with patch(
|
||||
"aiodns.DNSResolver.query", side_effect=aiodns.error.DNSError,
|
||||
):
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": SOURCE_USER}, data=USER_INPUT_PORT_TOO_LARGE
|
||||
)
|
||||
|
||||
assert result["type"] == RESULT_TYPE_FORM
|
||||
assert result["errors"] == {"base": "invalid_port"}
|
||||
assert result["type"] == RESULT_TYPE_FORM
|
||||
assert result["errors"] == {"base": "invalid_port"}
|
||||
|
||||
|
||||
async def test_connection_failed(hass: HomeAssistantType) -> None:
|
||||
"""Test error in case of a failed connection."""
|
||||
with patch("mcstatus.server.MinecraftServer.ping", side_effect=OSError):
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": SOURCE_USER}, data=USER_INPUT
|
||||
)
|
||||
with patch(
|
||||
"aiodns.DNSResolver.query", side_effect=aiodns.error.DNSError,
|
||||
):
|
||||
with patch("mcstatus.server.MinecraftServer.status", side_effect=OSError):
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": SOURCE_USER}, data=USER_INPUT
|
||||
)
|
||||
|
||||
assert result["type"] == RESULT_TYPE_FORM
|
||||
assert result["errors"] == {"base": "cannot_connect"}
|
||||
assert result["type"] == RESULT_TYPE_FORM
|
||||
assert result["errors"] == {"base": "cannot_connect"}
|
||||
|
||||
|
||||
async def test_connection_succeeded_with_srv_record(hass: HomeAssistantType) -> None:
|
||||
"""Test config entry in case of a successful connection with a SRV record."""
|
||||
with patch(
|
||||
"aiodns.DNSResolver.query", return_value=SRV_RECORDS,
|
||||
):
|
||||
with patch(
|
||||
"mcstatus.server.MinecraftServer.status",
|
||||
return_value=PingResponse(STATUS_RESPONSE_RAW),
|
||||
):
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": SOURCE_USER}, data=USER_INPUT_SRV
|
||||
)
|
||||
|
||||
assert result["type"] == RESULT_TYPE_CREATE_ENTRY
|
||||
assert result["title"] == USER_INPUT_SRV[CONF_HOST]
|
||||
assert result["data"][CONF_NAME] == USER_INPUT_SRV[CONF_NAME]
|
||||
assert result["data"][CONF_HOST] == USER_INPUT_SRV[CONF_HOST]
|
||||
|
||||
|
||||
async def test_connection_succeeded_with_host(hass: HomeAssistantType) -> None:
|
||||
"""Test config entry in case of a successful connection with a host name."""
|
||||
with patch("mcstatus.server.MinecraftServer.ping", return_value=50):
|
||||
with patch(
|
||||
"aiodns.DNSResolver.query", side_effect=aiodns.error.DNSError,
|
||||
):
|
||||
with patch(
|
||||
"mcstatus.server.MinecraftServer.status",
|
||||
return_value=PingResponse(STATUS_RESPONSE_RAW),
|
||||
@ -144,16 +202,17 @@ async def test_connection_succeeded_with_host(hass: HomeAssistantType) -> None:
|
||||
)
|
||||
|
||||
assert result["type"] == RESULT_TYPE_CREATE_ENTRY
|
||||
assert result["title"] == f"{USER_INPUT[CONF_HOST]}:{USER_INPUT[CONF_PORT]}"
|
||||
assert result["title"] == USER_INPUT[CONF_HOST]
|
||||
assert result["data"][CONF_NAME] == USER_INPUT[CONF_NAME]
|
||||
assert result["data"][CONF_HOST] == USER_INPUT[CONF_HOST]
|
||||
assert result["data"][CONF_PORT] == USER_INPUT[CONF_PORT]
|
||||
assert result["data"][CONF_HOST] == "mc.dummyserver.com"
|
||||
|
||||
|
||||
async def test_connection_succeeded_with_ip4(hass: HomeAssistantType) -> None:
|
||||
"""Test config entry in case of a successful connection with an IPv4 address."""
|
||||
with patch("getmac.get_mac_address", return_value="01:23:45:67:89:ab"):
|
||||
with patch("mcstatus.server.MinecraftServer.ping", return_value=50):
|
||||
with patch(
|
||||
"aiodns.DNSResolver.query", side_effect=aiodns.error.DNSError,
|
||||
):
|
||||
with patch(
|
||||
"mcstatus.server.MinecraftServer.status",
|
||||
return_value=PingResponse(STATUS_RESPONSE_RAW),
|
||||
@ -163,19 +222,17 @@ async def test_connection_succeeded_with_ip4(hass: HomeAssistantType) -> None:
|
||||
)
|
||||
|
||||
assert result["type"] == RESULT_TYPE_CREATE_ENTRY
|
||||
assert (
|
||||
result["title"]
|
||||
== f"{USER_INPUT_IPV4[CONF_HOST]}:{USER_INPUT_IPV4[CONF_PORT]}"
|
||||
)
|
||||
assert result["title"] == USER_INPUT_IPV4[CONF_HOST]
|
||||
assert result["data"][CONF_NAME] == USER_INPUT_IPV4[CONF_NAME]
|
||||
assert result["data"][CONF_HOST] == USER_INPUT_IPV4[CONF_HOST]
|
||||
assert result["data"][CONF_PORT] == USER_INPUT_IPV4[CONF_PORT]
|
||||
assert result["data"][CONF_HOST] == "1.1.1.1"
|
||||
|
||||
|
||||
async def test_connection_succeeded_with_ip6(hass: HomeAssistantType) -> None:
|
||||
"""Test config entry in case of a successful connection with an IPv6 address."""
|
||||
with patch("getmac.get_mac_address", return_value="01:23:45:67:89:ab"):
|
||||
with patch("mcstatus.server.MinecraftServer.ping", return_value=50):
|
||||
with patch(
|
||||
"aiodns.DNSResolver.query", side_effect=aiodns.error.DNSError,
|
||||
):
|
||||
with patch(
|
||||
"mcstatus.server.MinecraftServer.status",
|
||||
return_value=PingResponse(STATUS_RESPONSE_RAW),
|
||||
@ -185,10 +242,6 @@ async def test_connection_succeeded_with_ip6(hass: HomeAssistantType) -> None:
|
||||
)
|
||||
|
||||
assert result["type"] == RESULT_TYPE_CREATE_ENTRY
|
||||
assert (
|
||||
result["title"]
|
||||
== f"{USER_INPUT_IPV6[CONF_HOST]}:{USER_INPUT_IPV6[CONF_PORT]}"
|
||||
)
|
||||
assert result["title"] == USER_INPUT_IPV6[CONF_HOST]
|
||||
assert result["data"][CONF_NAME] == USER_INPUT_IPV6[CONF_NAME]
|
||||
assert result["data"][CONF_HOST] == USER_INPUT_IPV6[CONF_HOST]
|
||||
assert result["data"][CONF_PORT] == USER_INPUT_IPV6[CONF_PORT]
|
||||
assert result["data"][CONF_HOST] == "::ffff:0101:0101"
|
||||
|
Loading…
x
Reference in New Issue
Block a user