@@ -92,28 +92,42 @@ def expected_from_artifacts(build_root: Path) -> dict[tuple[str, str, str, str],
9292 target = m .group (1 )
9393 test_type = m .group (2 )
9494 print (f"[DEBUG] Artifact group target={ target } type={ test_type } dir={ artifact_dir } " , file = sys .stderr )
95- # Locate ci.yml next to build*.tmp folders and derive sketch/target
95+
96+ # Group build*.tmp directories by sketch to avoid processing same ci.yml multiple times
97+ # Structure: test-bin-<target>-<type>/<sketch>/build*.tmp/
98+ sketches_processed = set ()
99+
96100 for ci_path in artifact_dir .rglob ("ci.yml" ):
97101 if not ci_path .is_file ():
98102 continue
99103 build_tmp = ci_path .parent
100104 if not re .search (r"build\d*\.tmp$" , build_tmp .name ):
101105 continue
106+
107+ # Path structure is: test-bin-<target>-<type>/<sketch>/build*.tmp/ci.yml
102108 sketch = build_tmp .parent .name
103- target_guess = build_tmp .parent .parent .name if build_tmp .parent .parent else ""
104- if target_guess != target :
109+
110+ # Skip if we already processed this sketch (same ci.yml in multiple build*.tmp)
111+ if sketch in sketches_processed :
105112 continue
113+ sketches_processed .add (sketch )
114+
115+ print (f"[DEBUG] Processing sketch={ sketch } from artifact { artifact_dir .name } " , file = sys .stderr )
116+
106117 sdk_path = build_tmp / "sdkconfig"
107118 try :
108- ci_text = ci_path .read_text (encoding = "utf-8" ) if ci_path .exists () else ""
109- except Exception :
110- ci_text = ""
119+ ci_text = ci_path .read_text (encoding = "utf-8" )
120+ except Exception as e :
121+ print (f"[DEBUG] Skip (failed to read ci.yml: { e } )" , file = sys .stderr )
122+ continue
111123 try :
112124 sdk_text = sdk_path .read_text (encoding = "utf-8" , errors = "ignore" ) if sdk_path .exists () else ""
113125 except Exception :
114126 sdk_text = ""
127+
115128 ci = _parse_ci_yml (ci_text )
116129 fqbn_counts = _fqbn_counts_from_yaml (ci )
130+
117131 # Determine allowed platforms for this test
118132 allowed_platforms = []
119133 platforms_cfg = ci .get ("platforms" ) if isinstance (ci , dict ) else None
@@ -124,19 +138,26 @@ def expected_from_artifacts(build_root: Path) -> dict[tuple[str, str, str, str],
124138 if dis is False :
125139 continue
126140 allowed_platforms .append (plat )
141+
127142 # Requirements check
128143 minimal = {
129144 "requires" : ci .get ("requires" ) or [],
130145 "requires_any" : ci .get ("requires_any" ) or [],
131146 }
132147 if not _sdkconfig_meets (minimal , sdk_text ):
133- print (f"[DEBUG] Skip (requirements not met): target={ target } type={ test_type } sketch={ sketch } " , file = sys .stderr )
148+ print (f"[DEBUG] Skip (requirements not met): target={ target } type={ test_type } sketch={ sketch } " , file = sys .stderr )
134149 continue
135- # Expected runs per target driven by fqbn count; default 1 when 0
150+
151+ # Expected runs = number from fqbn_counts in ci.yml (how many FQBNs for this target)
136152 exp_runs = fqbn_counts .get (target , 0 ) or 1
153+ print (f"[DEBUG] ci.yml specifies { exp_runs } FQBN(s) for target={ target } " , file = sys .stderr )
154+
137155 for plat in allowed_platforms :
138- expected [(plat , target , test_type , sketch )] = max (expected .get ((plat , target , test_type , sketch ), 0 ), exp_runs )
139- print (f"[DEBUG] Expected: plat={ plat } target={ target } type={ test_type } sketch={ sketch } runs={ exp_runs } " , file = sys .stderr )
156+ expected [(plat , target , test_type , sketch )] = exp_runs
157+ print (f"[DEBUG] Expected: plat={ plat } target={ target } type={ test_type } sketch={ sketch } runs={ exp_runs } " , file = sys .stderr )
158+
159+ if len (sketches_processed ) == 0 :
160+ print (f"[DEBUG] No sketches found in this artifact group" , file = sys .stderr )
140161 return expected
141162
142163
@@ -181,10 +202,10 @@ def write_missing_xml(out_root: Path, platform: str, target: str, test_type: str
181202 # Create one XML per missing index
182203 for idx in range (missing_count ):
183204 suite_name = f"{ test_type } _{ platform } _{ target } _{ sketch } "
184- root = Element ("testsuite" , name = suite_name , tests = "1" , failures = "1 " , errors = "0 " )
205+ root = Element ("testsuite" , name = suite_name , tests = "1" , failures = "0 " , errors = "1 " )
185206 case = SubElement (root , "testcase" , classname = f"{ test_type } .{ sketch } " , name = "missing-run" )
186- fail = SubElement (case , "failure " , message = "Expected test run missing" )
187- fail .text = "This placeholder indicates an expected test run did not execute."
207+ error = SubElement (case , "error " , message = "Expected test run missing" )
208+ error .text = "This placeholder indicates an expected test run did not execute."
188209 tree = ElementTree (root )
189210 out_file = out_tests_dir / f"{ sketch } _missing_{ idx } .xml"
190211 tree .write (out_file , encoding = "utf-8" , xml_declaration = True )
0 commit comments