mirror of
https://github.com/esphome/esphome.git
synced 2026-10-01 17:00:21 +00:00
[esp8266] Use our own Arduino core builds for the native toolchain (#19876)
This commit is contained in:
@@ -2,9 +2,14 @@
|
||||
|
||||
import pytest
|
||||
|
||||
from esphome.components.esp8266 import _arduino_check_versions
|
||||
from esphome.components.esp8266 import (
|
||||
_arduino_check_versions,
|
||||
_format_framework_arduino_version,
|
||||
_framework_package_version,
|
||||
)
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_PLATFORM_VERSION, CONF_VERSION
|
||||
from esphome.core import EsphomeError
|
||||
|
||||
|
||||
def test_versions_before_3_are_rejected() -> None:
|
||||
@@ -21,3 +26,27 @@ def test_supported_versions_pass() -> None:
|
||||
value = _arduino_check_versions({CONF_VERSION: "recommended"})
|
||||
assert value[CONF_VERSION] == "3.1.2"
|
||||
assert "espressif8266@4.2.1" in value[CONF_PLATFORM_VERSION]
|
||||
|
||||
|
||||
def test_framework_package_version() -> None:
|
||||
assert _framework_package_version(cv.Version(3, 1, 2)) == "3.30102.0"
|
||||
assert _framework_package_version(cv.Version(3, 2, 0)) == "3.30200.0"
|
||||
# A future major bump needs its own encoding, not a doomed registry lookup
|
||||
with pytest.raises(EsphomeError, match="not supported yet"):
|
||||
_framework_package_version(cv.Version(4, 0, 0))
|
||||
# Cores before 3.x cannot build ESPHome (C++20) and are rejected
|
||||
with pytest.raises(EsphomeError, match="requires core 3"):
|
||||
_framework_package_version(cv.Version(2, 7, 4))
|
||||
|
||||
|
||||
def test_format_framework_arduino_version_pins_all_series() -> None:
|
||||
"""The PlatformIO source formatter across every encoding era."""
|
||||
|
||||
assert _format_framework_arduino_version(cv.Version(3, 1, 2)) == "~3.30102.0"
|
||||
# Pre-3 cores are rejected with the version line anchored
|
||||
with pytest.raises(cv.Invalid, match="requires core 3"):
|
||||
_format_framework_arduino_version(cv.Version(2, 7, 4))
|
||||
# Anchored to the framework version line, not a bare EsphomeError
|
||||
with pytest.raises(cv.Invalid, match="not supported yet") as excinfo:
|
||||
_format_framework_arduino_version(cv.Version(4, 0, 0))
|
||||
assert excinfo.value.path == ["version"]
|
||||
|
||||
@@ -67,21 +67,24 @@ def test_valid_config_passes() -> None:
|
||||
|
||||
|
||||
def test_platformio_toolchain_skips_checks() -> None:
|
||||
# 3.0.2 is pio-legal (>= the global 3.0.0 floor) but below the native
|
||||
# toolchain's own 3.1.1 floor; the bogus board only the native path checks
|
||||
# 3.0.2 is pio-legal (>= the global 3.0.0 floor) but has no native build;
|
||||
# the bogus board only the native path checks
|
||||
CORE.toolchain = Toolchain.PLATFORMIO
|
||||
config = _config(board="not_a_board", version="3.0.2")
|
||||
assert _validate_native_toolchain(config) is config
|
||||
|
||||
|
||||
def test_version_below_floor_rejected() -> None:
|
||||
# 3.1.0 has no registry package, so the native floor is 3.1.1
|
||||
with pytest.raises(cv.Invalid, match="3.1.1 or newer"):
|
||||
_validate_native_toolchain(_config(version="3.1.0"))
|
||||
def test_version_without_build_rejected() -> None:
|
||||
"""Only the core versions built in esphome-libs/arduino-esp8266 work."""
|
||||
with pytest.raises(
|
||||
cv.Invalid, match=r"3\.1\.1.*available: 3\.1\.2.*platformio"
|
||||
) as excinfo:
|
||||
_validate_native_toolchain(_config(version="3.1.1"))
|
||||
assert excinfo.value.path == [CONF_FRAMEWORK, CONF_VERSION]
|
||||
|
||||
|
||||
def test_version_at_floor_accepted() -> None:
|
||||
_validate_native_toolchain(_config(version="3.1.1"))
|
||||
def test_built_version_accepted() -> None:
|
||||
_validate_native_toolchain(_config(version="3.1.2"))
|
||||
|
||||
|
||||
def test_custom_platform_version_warns_and_is_dropped(
|
||||
|
||||
@@ -9,6 +9,7 @@ from unittest.mock import patch
|
||||
import pytest
|
||||
|
||||
from esphome.arduino8266 import framework
|
||||
from esphome.components.esp8266 import RECOMMENDED_ARDUINO_FRAMEWORK_VERSION
|
||||
import esphome.config_validation as cv
|
||||
from esphome.core import CORE, EsphomeError
|
||||
|
||||
@@ -18,32 +19,6 @@ def _build_path(tmp_path: Path) -> None:
|
||||
CORE.build_path = tmp_path
|
||||
|
||||
|
||||
def test_framework_package_version() -> None:
|
||||
assert framework.framework_package_version(cv.Version(3, 1, 2)) == "3.30102.0"
|
||||
assert framework.framework_package_version(cv.Version(3, 2, 0)) == "3.30200.0"
|
||||
# A future major bump needs its own encoding, not a doomed registry lookup
|
||||
with pytest.raises(EsphomeError, match="not supported yet"):
|
||||
framework.framework_package_version(cv.Version(4, 0, 0))
|
||||
# Cores before 3.x cannot build ESPHome (C++20) and are rejected
|
||||
with pytest.raises(EsphomeError, match="requires core 3"):
|
||||
framework.framework_package_version(cv.Version(2, 7, 4))
|
||||
|
||||
|
||||
def test_format_framework_arduino_version_pins_all_series() -> None:
|
||||
"""The esp8266 component's PIO source formatter across every encoding
|
||||
era, including the 4.x rejection it now shares with the installer."""
|
||||
from esphome.components.esp8266 import _format_framework_arduino_version as fmt
|
||||
|
||||
assert fmt(cv.Version(3, 1, 2)) == "~3.30102.0"
|
||||
# Pre-3 cores are rejected with the version line anchored
|
||||
with pytest.raises(cv.Invalid, match="requires core 3"):
|
||||
fmt(cv.Version(2, 7, 4))
|
||||
# Anchored to the framework version line, not a bare EsphomeError
|
||||
with pytest.raises(cv.Invalid, match="not supported yet") as excinfo:
|
||||
fmt(cv.Version(4, 0, 0))
|
||||
assert excinfo.value.path == ["version"]
|
||||
|
||||
|
||||
def test_tools_path_default_and_prefix(tmp_path: Path) -> None:
|
||||
with patch.dict(os.environ, {"ESPHOME_ARDUINO8266_PREFIX": str(tmp_path)}):
|
||||
assert framework.get_arduino8266_tools_path() == tmp_path.resolve()
|
||||
@@ -54,6 +29,27 @@ def test_tools_path_default_and_prefix(tmp_path: Path) -> None:
|
||||
assert path != Path.cwd()
|
||||
|
||||
|
||||
def _recommended() -> framework.FrameworkRelease:
|
||||
return framework.FRAMEWORK_RELEASES[RECOMMENDED_ARDUINO_FRAMEWORK_VERSION]
|
||||
|
||||
|
||||
def test_framework_releases_are_pinned() -> None:
|
||||
"""A release must not be pinned without its checksum, and the recommended
|
||||
core must have one."""
|
||||
assert RECOMMENDED_ARDUINO_FRAMEWORK_VERSION in framework.FRAMEWORK_RELEASES
|
||||
for version, release in framework.FRAMEWORK_RELEASES.items():
|
||||
assert release.tag.startswith(f"{version}-esphome.")
|
||||
assert len(release.sha256) == 64
|
||||
assert release.size > 0
|
||||
|
||||
|
||||
def test_framework_download() -> None:
|
||||
download = framework.FrameworkRelease("1.2.3-esphome.4", "a" * 64, 5).download()
|
||||
releases = "https://github.com/esphome-libs/arduino-esp8266/releases/"
|
||||
archive = "arduino-esp8266-1.2.3-esphome.4.tar.gz"
|
||||
assert download == (f"{releases}download/1.2.3-esphome.4/{archive}", "a" * 64, 5)
|
||||
|
||||
|
||||
def test_toolchain_builds_are_pinned() -> None:
|
||||
"""A release must not be pinned without its checksums."""
|
||||
for sha256, size in framework.TOOLCHAIN_BUILDS.values():
|
||||
@@ -86,14 +82,15 @@ def test_toolchain_download_unsupported_system() -> None:
|
||||
def _fake_framework(tmp_path: Path) -> None:
|
||||
"""The layout install_package expects of an installed framework."""
|
||||
for sub in ("cores/esp8266", "tools/sdk", "libraries"):
|
||||
(tmp_path / "frameworks" / "3.30102.0" / sub).mkdir(parents=True)
|
||||
(tmp_path / "frameworks" / "3.30102.0" / ".esphome_extracted").touch()
|
||||
(tmp_path / "frameworks" / _recommended().tag / sub).mkdir(parents=True)
|
||||
(tmp_path / "frameworks" / _recommended().tag / ".esphome_extracted").touch()
|
||||
|
||||
|
||||
def test_check_and_install_mirror_skips_pinned_toolchain(tmp_path: Path) -> None:
|
||||
"""With a mirror override an unsupported host can bring its own toolchain."""
|
||||
with (
|
||||
patch.dict(os.environ, {"ESPHOME_ARDUINO8266_PREFIX": str(tmp_path)}),
|
||||
patch.object(framework, "ESPHOME_ARDUINO8266_FRAMEWORK_MIRRORS", ["http://f"]),
|
||||
patch.object(framework, "ESPHOME_ARDUINO8266_TOOLCHAIN_MIRRORS", ["http://m"]),
|
||||
patch.object(framework, "install_package") as mock_install,
|
||||
patch.object(framework, "prefetch_packages") as mock_prefetch,
|
||||
@@ -101,7 +98,10 @@ def test_check_and_install_mirror_skips_pinned_toolchain(tmp_path: Path) -> None
|
||||
):
|
||||
framework.check_and_install(cv.Version(3, 1, 2))
|
||||
assert mock_prefetch.call_args.args[2] == {}
|
||||
assert mock_install.call_args_list[1].kwargs["resolve"] is None
|
||||
assert [call.kwargs["resolve"] for call in mock_install.call_args_list] == [
|
||||
None,
|
||||
None,
|
||||
]
|
||||
|
||||
|
||||
def test_check_and_install_installed_toolchain_on_unsupported_host(
|
||||
@@ -147,7 +147,7 @@ def test_check_and_install_returns_paths(tmp_path: Path) -> None:
|
||||
patch.object(framework, "find_ninja", return_value=tmp_path / "ninja"),
|
||||
):
|
||||
paths = framework.check_and_install(cv.Version(3, 1, 2))
|
||||
assert paths.framework == tmp_path / "frameworks" / "3.30102.0"
|
||||
assert paths.framework == tmp_path / "frameworks" / _recommended().tag
|
||||
assert paths.toolchain == tmp_path / "toolchains" / framework.TOOLCHAIN_VERSION
|
||||
assert paths.ninja == tmp_path / "ninja"
|
||||
assert mock_install.call_count == 2
|
||||
@@ -156,14 +156,14 @@ def test_check_and_install_returns_paths(tmp_path: Path) -> None:
|
||||
fw_call, tc_call = mock_install.call_args_list
|
||||
assert fw_call.args == (
|
||||
framework.FRAMEWORK_PACKAGE,
|
||||
"3.30102.0",
|
||||
tmp_path / "frameworks" / "3.30102.0",
|
||||
_recommended().tag,
|
||||
tmp_path / "frameworks" / _recommended().tag,
|
||||
framework.ESPHOME_ARDUINO8266_FRAMEWORK_MIRRORS,
|
||||
tmp_path / "downloads",
|
||||
)
|
||||
assert fw_call.kwargs == {
|
||||
"expect": ("cores/esp8266", "tools/sdk", "libraries"),
|
||||
"resolve": None,
|
||||
"resolve": _recommended().download,
|
||||
}
|
||||
assert tc_call.args == (
|
||||
framework.TOOLCHAIN_PACKAGE,
|
||||
@@ -181,8 +181,8 @@ def test_check_and_install_returns_paths(tmp_path: Path) -> None:
|
||||
[
|
||||
(
|
||||
framework.FRAMEWORK_PACKAGE,
|
||||
"3.30102.0",
|
||||
tmp_path / "frameworks" / "3.30102.0",
|
||||
_recommended().tag,
|
||||
tmp_path / "frameworks" / _recommended().tag,
|
||||
framework.ESPHOME_ARDUINO8266_FRAMEWORK_MIRRORS,
|
||||
),
|
||||
(
|
||||
@@ -193,7 +193,10 @@ def test_check_and_install_returns_paths(tmp_path: Path) -> None:
|
||||
),
|
||||
],
|
||||
tmp_path / "downloads",
|
||||
{framework.TOOLCHAIN_PACKAGE: framework.toolchain_download},
|
||||
{
|
||||
framework.FRAMEWORK_PACKAGE: _recommended().download,
|
||||
framework.TOOLCHAIN_PACKAGE: framework.toolchain_download,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -204,10 +207,10 @@ def test_get_build_env_prepends_toolchain_bin(tmp_path: Path) -> None:
|
||||
assert env["CCACHE_DIR"] == "x"
|
||||
|
||||
|
||||
def test_check_and_install_rejects_old_core(tmp_path: Path) -> None:
|
||||
"""Calling the installer below the floor fails before any download."""
|
||||
with pytest.raises(EsphomeError, match=">= 3.1.1"):
|
||||
framework.check_and_install(cv.Version(3, 0, 2))
|
||||
def test_check_and_install_rejects_unbuilt_core(tmp_path: Path) -> None:
|
||||
"""A core version without a build fails before any download."""
|
||||
with pytest.raises(EsphomeError, match=r"3\.1\.1.*available: 3\.1\.2"):
|
||||
framework.check_and_install(cv.Version(3, 1, 1))
|
||||
|
||||
|
||||
def test_get_build_env_without_path_has_no_empty_entry(tmp_path: Path) -> None:
|
||||
|
||||
Reference in New Issue
Block a user