mirror of
https://github.com/esphome/esphome.git
synced 2026-10-07 11:26:39 +00:00
Defer superseded wave downloads, dedupe tool dests, validate captured buckets, right-size the log levels
This commit is contained in:
@@ -940,6 +940,26 @@ def test_prefetch_all_entries_unverifiable_is_a_noop(tmp_path: Path) -> None:
|
||||
download.assert_not_called()
|
||||
|
||||
|
||||
def test_prefetch_dedupes_entries_by_dest(tmp_path: Path) -> None:
|
||||
"""Two entries resolving to one dest would interleave writes into the
|
||||
same .part file; only the first downloads."""
|
||||
entries = json.loads(_PREFETCH_JSON)
|
||||
dup = dict(entries[0]) | {"name": "cmake-alias@3.30.2"}
|
||||
entries.append(dup)
|
||||
with (
|
||||
patch(
|
||||
"esphome.espidf.framework.run_command",
|
||||
return_value=(True, json.dumps(entries), ""),
|
||||
),
|
||||
patch("esphome.espidf.framework.download_with_resume") as download,
|
||||
patch("esphome.espidf.framework.get_system_python_path", return_value="python"),
|
||||
patch("esphome.espidf.framework.BatchDownloadProgress"),
|
||||
):
|
||||
_prefetch_idf_tool_archives(tmp_path, "esp32", ["required"], None)
|
||||
dests = [call[0][1].name for call in download.call_args_list]
|
||||
assert dests.count("cmake-3.30.2.tar.gz") == 1
|
||||
|
||||
|
||||
def test_prefetch_downloads_each_archive_with_resume(tmp_path: Path) -> None:
|
||||
with (
|
||||
patch(
|
||||
|
||||
@@ -169,6 +169,30 @@ def test_apply_extra_script_callable_target_and_str_flags(tmp_path) -> None:
|
||||
assert c.data["build"]["flags"] == ["-DBASE=1", "-lesp8266"]
|
||||
|
||||
|
||||
def test_captured_nonstring_buckets_warn_and_skip(tmp_path, caplog) -> None:
|
||||
"""Non-string LIBS/LINKFLAGS/CPPFLAGS/LIBPATH entries (legal SCons
|
||||
nodes) are skipped by name instead of stringified into garbage flags."""
|
||||
(tmp_path / "src").mkdir()
|
||||
script = tmp_path / "extra.py"
|
||||
script.write_text(
|
||||
"env.Append(LIBS=['m', 42], LINKFLAGS=['-Wl,-x', {'no': 1}], "
|
||||
"CPPFLAGS=['-Os', 3.5], LIBPATH=['libs', 7])\n"
|
||||
)
|
||||
(tmp_path / "libs").mkdir()
|
||||
|
||||
c = IDFComponent("owner/name", "1.0", source=URLSource("http://dummy"))
|
||||
c.path = tmp_path
|
||||
c.data = {"build": {"extraScript": "extra.py"}}
|
||||
|
||||
apply_extra_script(c, board_mcu=lambda: "esp8266", pio_platform="espressif8266")
|
||||
|
||||
flags = c.data["build"]["flags"]
|
||||
assert "-lm" in flags and "-Wl,-x" in flags and "-Os" in flags
|
||||
assert not any("42" in f or "no" in f or "3.5" in f for f in flags)
|
||||
assert "Ignoring unsupported LIBS entry 42" in caplog.text
|
||||
assert "Ignoring unsupported LIBPATH entry 7" in caplog.text
|
||||
|
||||
|
||||
def test_captured_dict_cppdefines_warn_and_skip(tmp_path, caplog) -> None:
|
||||
"""A dict CPPDEFINES entry (legal SCons) must warn and skip; formatting
|
||||
it blind would hand the compiler -D{'FOO': '1'} garbage."""
|
||||
|
||||
@@ -255,6 +255,37 @@ def _patch_download_with_manifests(monkeypatch, tmp_path, manifests, *, properti
|
||||
_patch_registry_resolve(monkeypatch)
|
||||
|
||||
|
||||
def test_wave_requirement_growth_defers_the_superseded_download(tmp_path, monkeypatch):
|
||||
"""A's manifest constrains B while B sits in the same wave: B's
|
||||
drain-time resolution is superseded, so its download defers to the
|
||||
next wave instead of fetching a version that is immediately replaced."""
|
||||
download_names: list[str] = []
|
||||
manifests = {
|
||||
"esphome/A": {
|
||||
"name": "A",
|
||||
"build": {},
|
||||
"dependencies": {"esphome/B": ">=1.0"},
|
||||
},
|
||||
"esphome/B": {"name": "B", "build": {}},
|
||||
}
|
||||
|
||||
def fake_download(self, force=False, salt="", namespace="", progress=None):
|
||||
download_names.append(self.name)
|
||||
self.path = tmp_path / self.get_require_name()
|
||||
self.path.mkdir(parents=True, exist_ok=True)
|
||||
(self.path / "library.json").write_text(json.dumps(manifests[self.name]))
|
||||
|
||||
monkeypatch.setattr(ConvertedLibrary, "download", fake_download)
|
||||
_patch_registry_resolve(monkeypatch)
|
||||
top = convert_libraries(
|
||||
[Library("esphome/A", "1.0.0", None), Library("esphome/B", None, None)],
|
||||
_backend(),
|
||||
)
|
||||
assert sorted(c.name for c in top) == ["esphome/A", "esphome/B"]
|
||||
# B downloads exactly once, after its requirement set stabilized
|
||||
assert download_names.count("esphome/B") == 1
|
||||
|
||||
|
||||
def test_convert_libraries_parses_library_properties(tmp_path, monkeypatch):
|
||||
# A manifest provided as library.properties (Arduino style) instead of
|
||||
# library.json must still be parsed and converted.
|
||||
@@ -814,6 +845,7 @@ def test_walk_warns_for_properties_only_depends(
|
||||
{"esphome/A": "name=A\nversion=1.0\ndepends=Wire, SPI\n"},
|
||||
properties=("esphome/A",),
|
||||
)
|
||||
caplog.set_level("INFO")
|
||||
convert_libraries([Library("esphome/A", "1.0.0", None)], _backend())
|
||||
assert "declares dependencies via library.properties" in caplog.text
|
||||
|
||||
|
||||
Reference in New Issue
Block a user