build: standardize ESP32 3.3.11 test baseline

This commit is contained in:
2026-09-18 02:41:49 +10:00
parent ea6f1cf353
commit 3892ce1ca9
13 changed files with 108 additions and 100 deletions
+1 -3
View File
@@ -35,7 +35,7 @@ jobs:
strategy:
fail-fast: false
matrix:
platform: [esp8266, esp32, esp32_3_3_11]
platform: [esp8266, esp32]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
@@ -43,6 +43,4 @@ jobs:
python-version: '3.11'
- run: python -m pip install --upgrade platformio==6.1.19
- run: ./scripts/test.sh compile --platform ${{ matrix.platform }}
- if: matrix.platform == 'esp32_3_3_11'
run: ./scripts/test.sh packages --platform esp32_3_3_11
- run: ./scripts/test.sh examples --platform ${{ matrix.platform }}
-3
View File
@@ -51,9 +51,6 @@ jobs:
- run: pio test -e native --filter test_native_core
- run: ./scripts/test.sh compile --platform esp32
- run: ./scripts/test.sh examples --platform esp32
- run: ./scripts/test.sh compile --platform esp32_3_3_11
- run: ./scripts/test.sh packages --platform esp32_3_3_11
- run: ./scripts/test.sh examples --platform esp32_3_3_11
- run: ./scripts/check-docs.sh
- run: ./scripts/prepare-release.sh "$GITHUB_REF_NAME"
- run: ./scripts/release-notes.sh "$GITHUB_REF_NAME" > "$RUNNER_TEMP/release-notes.md"
+4 -4
View File
@@ -16,17 +16,17 @@ or application-source error.
ArduinoHA's root `pio test -e esp8266` environment and every guided ESP8266
PlatformIO example now use this same snapshot. There is no root-test exception
that can hide a linker regression from the example contract.
that can hide a linker regression from the example test harness.
Keep this exact framework snapshot in ESP8266 environments that need the
maintained test contract. It is unrelated to ESP32, whose pioarduino platform
maintained test harness. It is unrelated to ESP32, whose pioarduino platform
selects its framework and compiler as a unit. Do not replace the SHA with a
version range: remove or advance the pin only after an upstream release includes
the fix and the affected large firmware has compiled successfully. In
particular, changing the ESP32 validation lane does not justify changing this
ESP8266 pin.
The corresponding ESP32 Core 3 pin and shared PlatformIO-cache recovery steps
are documented in [DeviceFramework's toolchain guide](https://github.com/alexhopeoconnor/DeviceFramework/blob/main/docs/TOOLCHAINS.md).
The corresponding ESP32 Core 3.3.11 pin is documented in
[DeviceFramework's toolchain guide](https://github.com/alexhopeoconnor/DeviceFramework/blob/main/docs/TOOLCHAINS.md).
Back to the [documentation map](README.md).
+15 -19
View File
@@ -19,36 +19,33 @@ lifecycle handling, and tests are fork-native changes.
## Arduino framework validation lanes
ArduinoHA compiles its embedded test suites and guided PlatformIO examples in
three deliberately named lanes:
two maintained lanes:
| Selector | Target | Pinned stack | Role |
| --- | --- | --- | --- |
| `esp8266` | ESP8266 D1 mini | Arduino-ESP8266 commit `521ae60` | Maintained Postmortem linker-fix contract |
| `esp32` | ESP32 Dev Module | pioarduino `51.03.05` / Arduino-ESP32 3.0.5 | Legacy compatibility coverage |
| `esp32_3_3_11` | ESP32 Dev Module | pioarduino `55.03.311` / Arduino-ESP32 3.3.11 / ESP-IDF 5.5.5 | Current validation baseline |
| `esp8266` | ESP8266 D1 mini | Arduino-ESP8266 commit `521ae60` | Maintained Postmortem linker-fix test-harness lane |
| `esp32` | ESP32 Dev Module | pioarduino `55.03.311` / Arduino-ESP32 3.3.11 / ESP-IDF 5.5.5 | Maintained baseline |
The ESP32 3.0.5 lane remains intentional compatibility coverage until the
supported floor is changed in a reviewed release decision. It is not allowed to
select a framework or compiler from a global PlatformIO cache by accident;
every lane pins its complete pioarduino platform. The ESP8266 framework pin is
independent of both ESP32 lanes; see the [linker workaround](ESP8266-LINKER-WORKAROUND.md).
Every lane pins its complete framework stack. The ESP32 runner keeps its
maintained pioarduino graph in a persistent repository cache so stale global
metadata cannot select an uploader or compiler by accident. The ESP8266
framework pin is independent of the ESP32 baseline; see the [linker
workaround](ESP8266-LINKER-WORKAROUND.md).
Run the current ESP32 lane locally with:
```bash
./scripts/test.sh compile --platform esp32_3_3_11
./scripts/test.sh packages --platform esp32_3_3_11
./scripts/test.sh examples --platform esp32_3_3_11
./scripts/test.sh compile --platform esp32
./scripts/test.sh examples --platform esp32
```
The script keeps that current lane in a dedicated PlatformIO Core/cache
The script keeps that lane in a dedicated persistent PlatformIO Core/cache
directory by default (`${XDG_CACHE_HOME:-$HOME/.cache}/arduinoha-platformio/core-3.3.11`).
This prevents a legacy 3.0.5 `tool-esptoolpy` cache from shadowing the current
This prevents stale global `tool-esptoolpy` metadata from shadowing the current
pioarduino package-form uploader. Set `ARDUINOHA_PLATFORMIO_CORE_DIR`,
`ARDUINOHA_PLATFORMIO_PACKAGES_DIR`, and
`ARDUINOHA_PLATFORMIO_CACHE_DIR` for a dedicated disk or a disposable
clean-room check; do not repair this condition by overriding a single compiler
or deleting an unrelated global toolchain.
`ARDUINOHA_PLATFORMIO_CACHE_DIR` for a dedicated disk. The script never clears
that cache or repairs it by overriding one compiler package.
The embedded multi-suite compile path also defaults
`PLATFORMIO_RUN_JOBS=1`. A caller may explicitly set another value, but the
@@ -76,5 +73,4 @@ git diff --stat main...upstream/develop
Port only independently reviewed changes with regression tests; treat open
upstream pull requests as proposals, not release inputs. Run the native,
board-compile (including both ESP32 lanes), and HA test harness gates before
publishing a new release.
board-compile, and HA test harness gates before publishing a new release.
+1 -5
View File
@@ -16,13 +16,9 @@ platform_packages =
[env:esp32]
extends = common
platform = https://github.com/pioarduino/platform-espressif32/releases/download/51.03.05/platform-espressif32.zip
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.311/platform-espressif32.zip
board = esp32dev
build_unflags = -std=gnu++11
build_flags =
-std=gnu++14
-I${platformio.packages_dir}/framework-arduinoespressif32/libraries/Network/src
[env:esp32_3_3_11]
extends = env:esp32
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.311/platform-espressif32.zip
+1 -5
View File
@@ -16,13 +16,9 @@ platform_packages =
[env:esp32]
extends = common
platform = https://github.com/pioarduino/platform-espressif32/releases/download/51.03.05/platform-espressif32.zip
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.311/platform-espressif32.zip
board = esp32dev
build_unflags = -std=gnu++11
build_flags =
-std=gnu++14
-I${platformio.packages_dir}/framework-arduinoespressif32/libraries/Network/src
[env:esp32_3_3_11]
extends = env:esp32
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.311/platform-espressif32.zip
@@ -16,13 +16,9 @@ platform_packages =
[env:esp32]
extends = common
platform = https://github.com/pioarduino/platform-espressif32/releases/download/51.03.05/platform-espressif32.zip
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.311/platform-espressif32.zip
board = esp32dev
build_unflags = -std=gnu++11
build_flags =
-std=gnu++14
-I${platformio.packages_dir}/framework-arduinoespressif32/libraries/Network/src
[env:esp32_3_3_11]
extends = env:esp32
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.311/platform-espressif32.zip
+1 -5
View File
@@ -16,13 +16,9 @@ platform_packages =
[env:esp32]
extends = common
platform = https://github.com/pioarduino/platform-espressif32/releases/download/51.03.05/platform-espressif32.zip
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.311/platform-espressif32.zip
board = esp32dev
build_unflags = -std=gnu++11
build_flags =
-std=gnu++14
-I${platformio.packages_dir}/framework-arduinoespressif32/libraries/Network/src
[env:esp32_3_3_11]
extends = env:esp32
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.311/platform-espressif32.zip
+1 -3
View File
@@ -7,9 +7,7 @@ pio run -d examples/01-esp-sensor -e esp8266
pio run -d examples/01-esp-sensor -e esp8266 -t upload
```
The checked-in `esp32` environment preserves Arduino-ESP32 3.0.5 compatibility
coverage. Source-checkout maintenance also builds every guided project with
`esp32_3_3_11`, the Arduino-ESP32 3.3.11 validation lane. A consuming
The checked-in `esp32` environment uses Arduino-ESP32 3.3.11. A consuming
application should choose and pin its complete PlatformIO platform stack.
| Guided example | What it demonstrates |
+2 -9
View File
@@ -3,8 +3,7 @@
; Full suite:
; pio test -e esp8266
; pio test -e esp32
; ./scripts/test.sh compile --platform esp32_3_3_11
; (uses the isolated current Arduino-ESP32 validation lane)
; ./scripts/test.sh compile --platform esp32
;
; Single suite (examples):
; pio test -e esp8266 --filter test_utils_serializers
@@ -40,17 +39,11 @@ platform_packages =
[env:esp32]
extends = common
test_ignore = test_native_core
platform = https://github.com/pioarduino/platform-espressif32/releases/download/51.03.05/platform-espressif32.zip
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.311/platform-espressif32.zip
board = esp32dev
build_unflags = -std=gnu++11
build_flags = ${common.build_flags} -std=gnu++14
; Current Arduino-ESP32 validation lane. Keep the legacy env above until the
; supported floor changes through an explicit compatibility decision.
[env:esp32_3_3_11]
extends = env:esp32
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.311/platform-espressif32.zip
; Host-only regression checks for serialization, topic validation, and the
; PubSubClient mock path. The Arduino compatibility files live exclusively
; under test/native and are never included in firmware environments.
+6 -9
View File
@@ -2,27 +2,27 @@
set -euo pipefail
usage() {
echo "Usage: $0 compile|examples|packages --platform esp8266|esp32|esp32_3_3_11" >&2
echo "Usage: $0 compile|examples --platform esp8266|esp32" >&2
exit 2
}
[[ $# -eq 3 && ( "${1:-}" == "compile" || "${1:-}" == "examples" || "${1:-}" == "packages" ) && "${2:-}" == "--platform" ]] || usage
[[ $# -eq 3 && ( "${1:-}" == "compile" || "${1:-}" == "examples" ) && "${2:-}" == "--platform" ]] || usage
case "${3:-}" in
esp8266|esp32|esp32_3_3_11) environment="${3}" ;;
esp8266|esp32) environment="${3}" ;;
*) usage ;;
esac
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
pio_for_platform() {
if [[ "$environment" != "esp32_3_3_11" ]]; then
if [[ "$environment" != "esp32" ]]; then
pio "$@"
return
fi
# Keep Core 3.3.11's package-form esptool and generated pioarduino
# environment separate from the legacy Core 3.0.5 validation lane.
# A caller can point this at a disposable directory for cache diagnosis.
# environment in a persistent repository cache. It is never cleared by
# this script, and isolates this tested graph from stale global metadata.
local core_dir packages_dir cache_dir
core_dir="${ARDUINOHA_PLATFORMIO_CORE_DIR:-${XDG_CACHE_HOME:-$HOME/.cache}/arduinoha-platformio/core-3.3.11}"
packages_dir="${ARDUINOHA_PLATFORMIO_PACKAGES_DIR:-$core_dir/packages}"
@@ -42,9 +42,6 @@ case "$1" in
pio_for_platform test -d "$root" -e "$environment" --without-uploading --without-testing
echo "ArduinoHA compile check passed for $environment"
;;
packages)
pio_for_platform pkg list -d "$root" -e "$environment"
;;
examples)
mapfile -t examples < <(find "$root/examples" -mindepth 1 -maxdepth 1 -type d -name '[0-9][0-9]-*' -print | sort)
if (( ${#examples[@]} == 0 )); then
@@ -42,34 +42,34 @@ class HomeAssistantClient:
token_file = state / "ha-token"
cls.wait_until_ready(base_url)
if token_file.exists():
return cls(base_url, token_file.read_text(encoding="utf-8").strip())
client_id = "http://ha-mqtt-test-harness.local/"
user = {
"client_id": client_id,
"name": owner_name,
"username": username,
"password": password,
"language": "en",
}
created = cls._response_json(
requests.post(f"{base_url}/api/onboarding/users", json=user, timeout=10),
"Home Assistant onboarding user creation",
)
auth_code = created.get("auth_code")
if not auth_code:
raise TestHarnessError("Home Assistant onboarding did not return an auth_code")
token_response = cls._response_json(
requests.post(
f"{base_url}/auth/token",
data={"client_id": client_id, "grant_type": "authorization_code", "code": auth_code},
timeout=10,
),
"Home Assistant token exchange",
)
token = token_response.get("access_token")
if not token:
raise TestHarnessError("Home Assistant token exchange did not return an access_token")
token = token_file.read_text(encoding="utf-8").strip()
else:
client_id = "http://ha-mqtt-test-harness.local/"
user = {
"client_id": client_id,
"name": owner_name,
"username": username,
"password": password,
"language": "en",
}
created = cls._response_json(
requests.post(f"{base_url}/api/onboarding/users", json=user, timeout=10),
"Home Assistant onboarding user creation",
)
auth_code = created.get("auth_code")
if not auth_code:
raise TestHarnessError("Home Assistant onboarding did not return an auth_code")
token_response = cls._response_json(
requests.post(
f"{base_url}/auth/token",
data={"client_id": client_id, "grant_type": "authorization_code", "code": auth_code},
timeout=10,
),
"Home Assistant token exchange",
)
token = token_response.get("access_token")
if not token:
raise TestHarnessError("Home Assistant token exchange did not return an access_token")
client = cls(base_url, token)
for path, payload in (
@@ -81,6 +81,51 @@ class HomeAssistantClient:
raise TestHarnessError(
f"Home Assistant onboarding step {path} failed: {response.status_code} {response.text}"
)
# Complete the final server-side step before any browser test starts.
# Leaving it to first-login UI redirects makes a shared disposable
# instance timing-dependent and can leave it stuck on the onboarding
# route. Matching Home Assistant's own origin keeps the IndieAuth
# client and redirect URI locally verifiable.
integration_response = requests.post(
f"{base_url}/api/onboarding/integration",
headers=client._headers,
json={
"client_id": f"{base_url}/",
"redirect_uri": f"{base_url}/onboarding.html?auth_callback=1",
},
timeout=10,
)
if integration_response.status_code not in (200, 201, 400, 403, 404):
raise TestHarnessError(
"Home Assistant onboarding integration step failed: "
f"{integration_response.status_code} {integration_response.text}"
)
onboarding_response = requests.get(f"{base_url}/api/onboarding", timeout=10)
if not onboarding_response.ok:
raise TestHarnessError(
"Home Assistant onboarding status check failed: "
f"{onboarding_response.status_code} {onboarding_response.text}"
)
try:
onboarding_steps = onboarding_response.json()
except ValueError as error:
raise TestHarnessError("Home Assistant onboarding status returned invalid JSON") from error
if not isinstance(onboarding_steps, list):
raise TestHarnessError(
"Home Assistant onboarding status returned unexpected JSON: "
f"{onboarding_steps}"
)
pending_steps = [
str(step.get("step", "unknown"))
for step in onboarding_steps
if isinstance(step, dict) and step.get("done") is not True
]
if pending_steps:
raise TestHarnessError(
"Home Assistant onboarding remains incomplete after bootstrap: " + ", ".join(pending_steps)
)
state.mkdir(parents=True, exist_ok=True)
token_file.write_text(token, encoding="utf-8")
return client
+2 -2
View File
@@ -81,7 +81,7 @@ void onNativeStateChanged(HAMqtt::ConnectionState)
}
void test_json_helpers_escape_control_bytes_and_preserve_cursor_contract()
void test_json_helpers_escape_control_bytes_and_preserve_cursor_position()
{
const char value[] = "quote\" slash\\ newline\n tab\t control\x01";
char output[96] = {};
@@ -341,7 +341,7 @@ void tearDown(void) { }
int main(int, char**)
{
UNITY_BEGIN();
RUN_TEST(test_json_helpers_escape_control_bytes_and_preserve_cursor_contract);
RUN_TEST(test_json_helpers_escape_control_bytes_and_preserve_cursor_position);
RUN_TEST(test_availability_and_serializer_array_escape_json_values);
RUN_TEST(test_discovery_topic_tokens_are_rejected_before_topic_generation);
RUN_TEST(test_streaming_serializer_writes_exact_escaped_payload_to_mqtt_mock);