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: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
platform: [esp8266, esp32, esp32_3_3_11] platform: [esp8266, esp32]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-python@v5 - uses: actions/setup-python@v5
@@ -43,6 +43,4 @@ jobs:
python-version: '3.11' python-version: '3.11'
- run: python -m pip install --upgrade platformio==6.1.19 - run: python -m pip install --upgrade platformio==6.1.19
- run: ./scripts/test.sh compile --platform ${{ matrix.platform }} - 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 }} - 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: pio test -e native --filter test_native_core
- run: ./scripts/test.sh compile --platform esp32 - run: ./scripts/test.sh compile --platform esp32
- run: ./scripts/test.sh examples --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/check-docs.sh
- run: ./scripts/prepare-release.sh "$GITHUB_REF_NAME" - run: ./scripts/prepare-release.sh "$GITHUB_REF_NAME"
- run: ./scripts/release-notes.sh "$GITHUB_REF_NAME" > "$RUNNER_TEMP/release-notes.md" - 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 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 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 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 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 version range: remove or advance the pin only after an upstream release includes
the fix and the affected large firmware has compiled successfully. In the fix and the affected large firmware has compiled successfully. In
particular, changing the ESP32 validation lane does not justify changing this particular, changing the ESP32 validation lane does not justify changing this
ESP8266 pin. ESP8266 pin.
The corresponding ESP32 Core 3 pin and shared PlatformIO-cache recovery steps The corresponding ESP32 Core 3.3.11 pin is documented in
are documented in [DeviceFramework's toolchain guide](https://github.com/alexhopeoconnor/DeviceFramework/blob/main/docs/TOOLCHAINS.md). [DeviceFramework's toolchain guide](https://github.com/alexhopeoconnor/DeviceFramework/blob/main/docs/TOOLCHAINS.md).
Back to the [documentation map](README.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 ## Arduino framework validation lanes
ArduinoHA compiles its embedded test suites and guided PlatformIO examples in ArduinoHA compiles its embedded test suites and guided PlatformIO examples in
three deliberately named lanes: two maintained lanes:
| Selector | Target | Pinned stack | Role | | Selector | Target | Pinned stack | Role |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| `esp8266` | ESP8266 D1 mini | Arduino-ESP8266 commit `521ae60` | Maintained Postmortem linker-fix contract | | `esp8266` | ESP8266 D1 mini | Arduino-ESP8266 commit `521ae60` | Maintained Postmortem linker-fix test-harness lane |
| `esp32` | ESP32 Dev Module | pioarduino `51.03.05` / Arduino-ESP32 3.0.5 | Legacy compatibility coverage | | `esp32` | ESP32 Dev Module | pioarduino `55.03.311` / Arduino-ESP32 3.3.11 / ESP-IDF 5.5.5 | Maintained baseline |
| `esp32_3_3_11` | ESP32 Dev Module | pioarduino `55.03.311` / Arduino-ESP32 3.3.11 / ESP-IDF 5.5.5 | Current validation baseline |
The ESP32 3.0.5 lane remains intentional compatibility coverage until the Every lane pins its complete framework stack. The ESP32 runner keeps its
supported floor is changed in a reviewed release decision. It is not allowed to maintained pioarduino graph in a persistent repository cache so stale global
select a framework or compiler from a global PlatformIO cache by accident; metadata cannot select an uploader or compiler by accident. The ESP8266
every lane pins its complete pioarduino platform. The ESP8266 framework pin is framework pin is independent of the ESP32 baseline; see the [linker
independent of both ESP32 lanes; see the [linker workaround](ESP8266-LINKER-WORKAROUND.md). workaround](ESP8266-LINKER-WORKAROUND.md).
Run the current ESP32 lane locally with: Run the current ESP32 lane locally with:
```bash ```bash
./scripts/test.sh compile --platform esp32_3_3_11 ./scripts/test.sh compile --platform esp32
./scripts/test.sh packages --platform esp32_3_3_11 ./scripts/test.sh examples --platform esp32
./scripts/test.sh examples --platform esp32_3_3_11
``` ```
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`). 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`, pioarduino package-form uploader. Set `ARDUINOHA_PLATFORMIO_CORE_DIR`,
`ARDUINOHA_PLATFORMIO_PACKAGES_DIR`, and `ARDUINOHA_PLATFORMIO_PACKAGES_DIR`, and
`ARDUINOHA_PLATFORMIO_CACHE_DIR` for a dedicated disk or a disposable `ARDUINOHA_PLATFORMIO_CACHE_DIR` for a dedicated disk. The script never clears
clean-room check; do not repair this condition by overriding a single compiler that cache or repairs it by overriding one compiler package.
or deleting an unrelated global toolchain.
The embedded multi-suite compile path also defaults The embedded multi-suite compile path also defaults
`PLATFORMIO_RUN_JOBS=1`. A caller may explicitly set another value, but the `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 Port only independently reviewed changes with regression tests; treat open
upstream pull requests as proposals, not release inputs. Run the native, upstream pull requests as proposals, not release inputs. Run the native,
board-compile (including both ESP32 lanes), and HA test harness gates before board-compile, and HA test harness gates before publishing a new release.
publishing a new release.
+1 -5
View File
@@ -16,13 +16,9 @@ platform_packages =
[env:esp32] [env:esp32]
extends = common 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 board = esp32dev
build_unflags = -std=gnu++11 build_unflags = -std=gnu++11
build_flags = build_flags =
-std=gnu++14 -std=gnu++14
-I${platformio.packages_dir}/framework-arduinoespressif32/libraries/Network/src -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] [env:esp32]
extends = common 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 board = esp32dev
build_unflags = -std=gnu++11 build_unflags = -std=gnu++11
build_flags = build_flags =
-std=gnu++14 -std=gnu++14
-I${platformio.packages_dir}/framework-arduinoespressif32/libraries/Network/src -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] [env:esp32]
extends = common 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 board = esp32dev
build_unflags = -std=gnu++11 build_unflags = -std=gnu++11
build_flags = build_flags =
-std=gnu++14 -std=gnu++14
-I${platformio.packages_dir}/framework-arduinoespressif32/libraries/Network/src -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] [env:esp32]
extends = common 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 board = esp32dev
build_unflags = -std=gnu++11 build_unflags = -std=gnu++11
build_flags = build_flags =
-std=gnu++14 -std=gnu++14
-I${platformio.packages_dir}/framework-arduinoespressif32/libraries/Network/src -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 pio run -d examples/01-esp-sensor -e esp8266 -t upload
``` ```
The checked-in `esp32` environment preserves Arduino-ESP32 3.0.5 compatibility The checked-in `esp32` environment uses Arduino-ESP32 3.3.11. A consuming
coverage. Source-checkout maintenance also builds every guided project with
`esp32_3_3_11`, the Arduino-ESP32 3.3.11 validation lane. A consuming
application should choose and pin its complete PlatformIO platform stack. application should choose and pin its complete PlatformIO platform stack.
| Guided example | What it demonstrates | | Guided example | What it demonstrates |
+2 -9
View File
@@ -3,8 +3,7 @@
; Full suite: ; Full suite:
; pio test -e esp8266 ; pio test -e esp8266
; pio test -e esp32 ; pio test -e esp32
; ./scripts/test.sh compile --platform esp32_3_3_11 ; ./scripts/test.sh compile --platform esp32
; (uses the isolated current Arduino-ESP32 validation lane)
; ;
; Single suite (examples): ; Single suite (examples):
; pio test -e esp8266 --filter test_utils_serializers ; pio test -e esp8266 --filter test_utils_serializers
@@ -40,17 +39,11 @@ platform_packages =
[env:esp32] [env:esp32]
extends = common extends = common
test_ignore = test_native_core 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 board = esp32dev
build_unflags = -std=gnu++11 build_unflags = -std=gnu++11
build_flags = ${common.build_flags} -std=gnu++14 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 ; Host-only regression checks for serialization, topic validation, and the
; PubSubClient mock path. The Arduino compatibility files live exclusively ; PubSubClient mock path. The Arduino compatibility files live exclusively
; under test/native and are never included in firmware environments. ; under test/native and are never included in firmware environments.
+6 -9
View File
@@ -2,27 +2,27 @@
set -euo pipefail set -euo pipefail
usage() { 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 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 case "${3:-}" in
esp8266|esp32|esp32_3_3_11) environment="${3}" ;; esp8266|esp32) environment="${3}" ;;
*) usage ;; *) usage ;;
esac esac
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
pio_for_platform() { pio_for_platform() {
if [[ "$environment" != "esp32_3_3_11" ]]; then if [[ "$environment" != "esp32" ]]; then
pio "$@" pio "$@"
return return
fi fi
# Keep Core 3.3.11's package-form esptool and generated pioarduino # Keep Core 3.3.11's package-form esptool and generated pioarduino
# environment separate from the legacy Core 3.0.5 validation lane. # environment in a persistent repository cache. It is never cleared by
# A caller can point this at a disposable directory for cache diagnosis. # this script, and isolates this tested graph from stale global metadata.
local core_dir packages_dir cache_dir local core_dir packages_dir cache_dir
core_dir="${ARDUINOHA_PLATFORMIO_CORE_DIR:-${XDG_CACHE_HOME:-$HOME/.cache}/arduinoha-platformio/core-3.3.11}" 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}" 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 pio_for_platform test -d "$root" -e "$environment" --without-uploading --without-testing
echo "ArduinoHA compile check passed for $environment" echo "ArduinoHA compile check passed for $environment"
;; ;;
packages)
pio_for_platform pkg list -d "$root" -e "$environment"
;;
examples) examples)
mapfile -t examples < <(find "$root/examples" -mindepth 1 -maxdepth 1 -type d -name '[0-9][0-9]-*' -print | sort) mapfile -t examples < <(find "$root/examples" -mindepth 1 -maxdepth 1 -type d -name '[0-9][0-9]-*' -print | sort)
if (( ${#examples[@]} == 0 )); then if (( ${#examples[@]} == 0 )); then
@@ -42,34 +42,34 @@ class HomeAssistantClient:
token_file = state / "ha-token" token_file = state / "ha-token"
cls.wait_until_ready(base_url) cls.wait_until_ready(base_url)
if token_file.exists(): if token_file.exists():
return cls(base_url, token_file.read_text(encoding="utf-8").strip()) token = token_file.read_text(encoding="utf-8").strip()
else:
client_id = "http://ha-mqtt-test-harness.local/" client_id = "http://ha-mqtt-test-harness.local/"
user = { user = {
"client_id": client_id, "client_id": client_id,
"name": owner_name, "name": owner_name,
"username": username, "username": username,
"password": password, "password": password,
"language": "en", "language": "en",
} }
created = cls._response_json( created = cls._response_json(
requests.post(f"{base_url}/api/onboarding/users", json=user, timeout=10), requests.post(f"{base_url}/api/onboarding/users", json=user, timeout=10),
"Home Assistant onboarding user creation", "Home Assistant onboarding user creation",
) )
auth_code = created.get("auth_code") auth_code = created.get("auth_code")
if not auth_code: if not auth_code:
raise TestHarnessError("Home Assistant onboarding did not return an auth_code") raise TestHarnessError("Home Assistant onboarding did not return an auth_code")
token_response = cls._response_json( token_response = cls._response_json(
requests.post( requests.post(
f"{base_url}/auth/token", f"{base_url}/auth/token",
data={"client_id": client_id, "grant_type": "authorization_code", "code": auth_code}, data={"client_id": client_id, "grant_type": "authorization_code", "code": auth_code},
timeout=10, timeout=10,
), ),
"Home Assistant token exchange", "Home Assistant token exchange",
) )
token = token_response.get("access_token") token = token_response.get("access_token")
if not token: if not token:
raise TestHarnessError("Home Assistant token exchange did not return an access_token") raise TestHarnessError("Home Assistant token exchange did not return an access_token")
client = cls(base_url, token) client = cls(base_url, token)
for path, payload in ( for path, payload in (
@@ -81,6 +81,51 @@ class HomeAssistantClient:
raise TestHarnessError( raise TestHarnessError(
f"Home Assistant onboarding step {path} failed: {response.status_code} {response.text}" 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) state.mkdir(parents=True, exist_ok=True)
token_file.write_text(token, encoding="utf-8") token_file.write_text(token, encoding="utf-8")
return client 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"; const char value[] = "quote\" slash\\ newline\n tab\t control\x01";
char output[96] = {}; char output[96] = {};
@@ -341,7 +341,7 @@ void tearDown(void) { }
int main(int, char**) int main(int, char**)
{ {
UNITY_BEGIN(); 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_availability_and_serializer_array_escape_json_values);
RUN_TEST(test_discovery_topic_tokens_are_rejected_before_topic_generation); RUN_TEST(test_discovery_topic_tokens_are_rejected_before_topic_generation);
RUN_TEST(test_streaming_serializer_writes_exact_escaped_payload_to_mqtt_mock); RUN_TEST(test_streaming_serializer_writes_exact_escaped_payload_to_mqtt_mock);