Skip to content

Commit 7b6250e

Browse files
authored
Merge branch 'master' into master
2 parents 32243ab + 37ef130 commit 7b6250e

File tree

10 files changed

+424
-206
lines changed

10 files changed

+424
-206
lines changed

.github/CI_README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -604,7 +604,7 @@ requires:
604604
Some tests require two physical devices (e.g., BLE server/client, WiFi AP/client). These are defined using the `multi_device` field in `ci.yml`, where each entry points to a sketch directory for that device.
605605

606606
**How it works:**
607-
- `tests_build.sh` builds each device sketch separately and stores artifacts under `~/.arduino/tests/<target>/<test>_<sketch>/build.tmp`.
607+
- `tests_build.sh` builds each device sketch separately and stores artifacts under `~/.arduino/tests/<target>/<test>/<sketch>/build.tmp`.
608608
- `tests_run.sh` assembles multiple build directories and ports using `|` separators, then runs pytest with `--count` and `--embedded-services` for each DUT.
609609
- Only **2 devices** are supported currently.
610610
- **Hardware only**: multi-device tests are blocked for Wokwi and QEMU.

.github/scripts/generate_missing_junits.py

Lines changed: 15 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -100,29 +100,29 @@ def expected_from_artifacts(build_root: Path) -> dict[tuple[str, str, str, str],
100100
test_type = m.group(2)
101101
print(f"[DEBUG] Artifact group target={target} type={test_type} dir={artifact_dir}", file=sys.stderr)
102102

103-
# Group build*.tmp directories by sketch
104-
# Structure: test-bin-<target>-<type>/<sketch>/build*.tmp/
105-
sketches_processed = set()
106-
# Track multi-device test names to avoid counting them multiple times
107-
# (e.g., wifi_ap_ap and wifi_ap_client both map to test name wifi_ap)
108-
multi_device_tests_processed = set()
109-
110-
# Find all build*.tmp directories and process each sketch once
103+
# Find all build*.tmp directories and determine test names.
104+
# Directory layout:
105+
# Single-device: test-bin-<target>-<type>/<test>/build*.tmp/
106+
# Multi-device: test-bin-<target>-<type>/<test>/<device>/build*.tmp/
107+
# The test name is always the first path component after the artifact group.
108+
tests_processed = set()
109+
111110
for build_tmp in artifact_dir.rglob("build*.tmp"):
112111
if not build_tmp.is_dir():
113112
continue
114113
if not re.search(r"build\d*\.tmp$", build_tmp.name):
115114
continue
116115

117-
# Path structure is: test-bin-<target>-<type>/<sketch>/build*.tmp/
118-
sketch = build_tmp.parent.name
116+
# Test name is always the first directory component after the artifact group
117+
rel = build_tmp.relative_to(artifact_dir)
118+
effective_sketch = rel.parts[0]
119119

120-
# Skip if we already processed this sketch
121-
if sketch in sketches_processed:
120+
# Skip if we already processed this test
121+
if effective_sketch in tests_processed:
122122
continue
123-
sketches_processed.add(sketch)
123+
tests_processed.add(effective_sketch)
124124

125-
print(f"[DEBUG] Processing sketch={sketch} from artifact {artifact_dir.name}", file=sys.stderr)
125+
print(f"[DEBUG] Processing test={effective_sketch} from artifact {artifact_dir.name}", file=sys.stderr)
126126

127127
ci_path = build_tmp / "ci.yml"
128128
sdk_path = build_tmp / "sdkconfig"
@@ -146,26 +146,6 @@ def expected_from_artifacts(build_root: Path) -> dict[tuple[str, str, str, str],
146146
ci = _parse_ci_yml(ci_text)
147147
fqbn_counts = _fqbn_counts_from_yaml(ci)
148148

149-
# For multi-device tests, the build artifact sketch name follows the
150-
# pattern {test_name}_{device_sketch} (e.g., wifi_ap_ap, wifi_ap_client).
151-
# Derive the original test name to match the test result XML structure,
152-
# which uses the test name (e.g., validation/wifi_ap/esp32/wifi_ap.xml).
153-
effective_sketch = sketch
154-
multi_device = ci.get("multi_device") if isinstance(ci, dict) else None
155-
if isinstance(multi_device, dict):
156-
device_names = [str(v) for v in multi_device.values()]
157-
for dname in device_names:
158-
suffix = f"_{dname}"
159-
if sketch.endswith(suffix):
160-
effective_sketch = sketch[:-len(suffix)]
161-
break
162-
# Only process each multi-device test once across all its device sketches
163-
if effective_sketch in multi_device_tests_processed:
164-
print(f"[DEBUG] Skip (multi-device test already processed): {sketch} -> {effective_sketch}", file=sys.stderr)
165-
continue
166-
multi_device_tests_processed.add(effective_sketch)
167-
print(f"[DEBUG] Multi-device test detected: {sketch} -> {effective_sketch}", file=sys.stderr)
168-
169149
# Determine allowed platforms for this test
170150
# Performance tests are only run on hardware
171151
if test_type == "performance":
@@ -198,7 +178,7 @@ def expected_from_artifacts(build_root: Path) -> dict[tuple[str, str, str, str],
198178
expected[(plat, target, test_type, effective_sketch)] = exp_runs
199179
print(f"[DEBUG] Expected: plat={plat} target={target} type={test_type} sketch={effective_sketch} runs={exp_runs}", file=sys.stderr)
200180

201-
if len(sketches_processed) == 0:
181+
if len(tests_processed) == 0:
202182
print(f"[DEBUG] No sketches found in this artifact group", file=sys.stderr)
203183
return expected
204184

.github/scripts/sketch_utils.sh

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@ function build_sketch { # build_sketch <ide_path> <user_path> <path-to-ino> [ext
102102
shift
103103
ci_yml_dir=$1
104104
;;
105+
-bn )
106+
shift
107+
build_name=$1
108+
;;
105109
* )
106110
break
107111
;;
@@ -132,13 +136,23 @@ function build_sketch { # build_sketch <ide_path> <user_path> <path-to-ino> [ext
132136
# precedence. Note that the following logic also falls to the default
133137
# parameters if no arguments were passed and no file was found.
134138

135-
if [ -z "$options" ] && [ -f "$sketchdir"/ci.yml ]; then
139+
# Resolve which ci.yml to use for FQBN / fqbn_append lookups.
140+
# For multi-device tests (-td), the sub-sketch directory does not
141+
# contain its own ci.yml; the parent test directory does.
142+
local ci_yml_for_build=""
143+
if [ -f "$sketchdir"/ci.yml ]; then
144+
ci_yml_for_build="$sketchdir/ci.yml"
145+
elif [ -n "$ci_yml_dir" ] && [ -f "$ci_yml_dir/ci.yml" ]; then
146+
ci_yml_for_build="$ci_yml_dir/ci.yml"
147+
fi
148+
149+
if [ -z "$options" ] && [ -n "$ci_yml_for_build" ]; then
136150
# The config file could contain multiple FQBNs for one chip. If
137151
# that's the case we build one time for every FQBN.
138152

139-
len=$(yq eval ".fqbn.${target} | length" "$sketchdir"/ci.yml 2>/dev/null || echo 0)
153+
len=$(yq eval ".fqbn.${target} | length" "$ci_yml_for_build" 2>/dev/null || echo 0)
140154
if [ "$len" -gt 0 ]; then
141-
fqbn=$(yq eval ".fqbn.${target} | sort | @json" "$sketchdir"/ci.yml)
155+
fqbn=$(yq eval ".fqbn.${target} | sort | @json" "$ci_yml_for_build")
142156
fi
143157
fi
144158

@@ -148,8 +162,8 @@ function build_sketch { # build_sketch <ide_path> <user_path> <path-to-ino> [ext
148162

149163
len=1
150164

151-
if [ -f "$sketchdir"/ci.yml ]; then
152-
fqbn_append=$(yq eval '.fqbn_append' "$sketchdir"/ci.yml 2>/dev/null)
165+
if [ -n "$ci_yml_for_build" ]; then
166+
fqbn_append=$(yq eval '.fqbn_append' "$ci_yml_for_build" 2>/dev/null)
153167
if [ "$fqbn_append" == "null" ]; then
154168
fqbn_append=""
155169
fi
@@ -228,14 +242,6 @@ function build_sketch { # build_sketch <ide_path> <user_path> <path-to-ino> [ext
228242
exit 1
229243
fi
230244

231-
# The directory that will hold all the artifacts (the build directory) is
232-
# provided through:
233-
# 1. An env variable called ARDUINO_BUILD_DIR.
234-
# 2. Created at the sketch level as "build" in the case of a single
235-
# configuration test.
236-
# 3. Created at the sketch level as "buildX" where X is the number
237-
# of configuration built in case of a multiconfiguration test.
238-
239245
sketchname=$(basename "$sketchdir")
240246
local has_requirements
241247

@@ -255,29 +261,36 @@ function build_sketch { # build_sketch <ide_path> <user_path> <path-to-ino> [ext
255261
fi
256262

257263
# Install libraries from ci.yml if they exist
258-
install_libs -ai "$ide_path" -s "$sketchdir"
264+
local ci_yml_lib_dir="${ci_yml_dir:-$sketchdir}"
265+
install_libs -ai "$ide_path" -s "$ci_yml_lib_dir"
259266
install_result=$?
260267
if [ $install_result -ne 0 ]; then
261268
echo "ERROR: Library installation failed for $sketchname" >&2
262269
exit $install_result
263270
fi
264271

265-
ARDUINO_CACHE_DIR="$HOME/.arduino/cache.tmp"
266-
if [ -n "$ARDUINO_BUILD_DIR" ]; then
267-
build_dir="$ARDUINO_BUILD_DIR"
268-
elif [ "$len" -eq 1 ]; then
269-
# build_dir="$sketchdir/build"
270-
build_dir="$HOME/.arduino/tests/$target/$sketchname/build.tmp"
271-
fi
272+
# Build directory path:
273+
# ARDUINO_BUILD_DIR env var → full override (used by on-push.sh for non-test builds)
274+
# Otherwise → ~/.arduino/tests/$target/$build_output_name/build[N].tmp
275+
# -bn sets a parent directory (test name) for multi-device builds:
276+
# e.g. -bn wifi_ap + sketchname=ap → wifi_ap/ap/build.tmp
277+
# Without -bn, uses $sketchname directly:
278+
# e.g. sketchname=gpio → gpio/build.tmp
279+
local build_output_name="${build_name:+$build_name/}$sketchname"
272280

281+
ARDUINO_CACHE_DIR="$HOME/.arduino/cache.tmp"
273282
output_file="$HOME/.arduino/cli_compile_output.txt"
274283
sizes_file="$GITHUB_WORKSPACE/cli_compile_$chunk_index.json"
275284

276285
mkdir -p "$ARDUINO_CACHE_DIR"
277286
for i in $(seq 0 $((len - 1))); do
278-
if [ "$len" -ne 1 ]; then
279-
# build_dir="$sketchdir/build$i"
280-
build_dir="$HOME/.arduino/tests/$target/$sketchname/build$i.tmp"
287+
if [ -n "$ARDUINO_BUILD_DIR" ]; then
288+
# Full override from env var (non-test builds like on-push.sh)
289+
build_dir="$ARDUINO_BUILD_DIR"
290+
elif [ "$len" -eq 1 ]; then
291+
build_dir="$HOME/.arduino/tests/$target/$build_output_name/build.tmp"
292+
else
293+
build_dir="$HOME/.arduino/tests/$target/$build_output_name/build$i.tmp"
281294
fi
282295
rm -rf "$build_dir"
283296
mkdir -p "$build_dir"

.github/scripts/tests_build.sh

Lines changed: 8 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -64,34 +64,6 @@ function extract_target_and_args {
6464
done
6565
}
6666

67-
# Build a single sketch for multi-device tests
68-
function build_multi_device_sketch {
69-
local test_name=$1
70-
local sketch_path=$2
71-
local target=$3
72-
shift 3
73-
local build_args=("$@")
74-
local sketch_dir
75-
local sketch_name
76-
local test_dir
77-
local build_dir
78-
79-
sketch_dir=$(dirname "$sketch_path")
80-
sketch_name=$(basename "$sketch_dir")
81-
test_dir=$(dirname "$sketch_dir")
82-
83-
# Override build directory to use <test_name>_<sketch_name> pattern
84-
build_dir="$HOME/.arduino/tests/$target/${test_name}_${sketch_name}/build.tmp"
85-
86-
echo "Building sketch $sketch_name for multi-device test $test_name"
87-
88-
# Call sketch_utils.sh build function with custom build directory
89-
# Pass -td to point to the parent test directory where ci.yml lives,
90-
# since individual sub-sketch directories don't have their own ci.yml.
91-
ARDUINO_BUILD_DIR="$build_dir" ${SKETCH_UTILS} build "${build_args[@]}" -s "$sketch_dir" -td "$test_dir"
92-
return $?
93-
}
94-
9567
# Build all sketches for a multi-device test
9668
function build_multi_device_test {
9769
local test_dir=$1
@@ -133,16 +105,23 @@ function build_multi_device_test {
133105
local result=0
134106
local sketch_name
135107
local sketch_path
108+
local sketch_dir
136109
for device in $devices; do
137110
sketch_name=$(yq eval ".multi_device.$device" "$test_dir/ci.yml" 2>/dev/null)
138111
sketch_path="$test_dir/$sketch_name/$sketch_name.ino"
112+
sketch_dir="$test_dir/$sketch_name"
139113

140114
if [ ! -f "$sketch_path" ]; then
141115
echo "ERROR: Sketch not found: $sketch_path"
142116
return 1
143117
fi
144118

145-
build_multi_device_sketch "$test_name" "$sketch_path" "$target" "${build_args[@]}"
119+
echo "Building sketch $sketch_name for multi-device test $test_name"
120+
121+
# -td: ci.yml lives in the parent test directory
122+
# -bn: sets the parent build dir to the test name (nested: $test_name/$sketch_name/build.tmp)
123+
${SKETCH_UTILS} build "${build_args[@]}" -s "$sketch_dir" \
124+
-td "$test_dir" -bn "$test_name"
146125
result=$?
147126
if [ $result -ne 0 ]; then
148127
echo "ERROR: Failed to build sketch $sketch_name for test $test_name"

0 commit comments

Comments
 (0)