bneradt commented on code in PR #13540:
URL: https://github.com/apache/trafficserver/pull/13540#discussion_r3908004515


##########
tests/autest-parallel.py.in:
##########
@@ -227,6 +227,37 @@ def strip_ansi(text: str) -> str:
     return ansi_escape.sub('', text)
 
 
+def parse_test_completion(line: str) -> Optional[Tuple[str, str]]:
+    """Extract a completed test name and status from an autest progress 
line."""
+    clean = strip_ansi(line).strip()
+    marker = 'Running Test '
+    marker_pos = clean.rfind(marker)
+
+    if marker_pos < 0:
+        return None
+
+    completion = clean[marker_pos + len(marker):]
+    match = re.match(r'([^:\s]+):.*\b(Passed|Failed|Skipped)\s*$', completion, 
re.IGNORECASE)

Review Comment:
   Fixed in 483ffc8c28. Timing completion parsing now accepts Unknown, Skipped, 
Passed, Warning, Failed, and Exception in both combined and detached output, 
with stable short labels for all six. This keeps last_completion and saved 
per-test timings aligned for every terminal state.



##########
tests/autest-parallel.py.in:
##########
@@ -517,151 +548,150 @@ def run_worker(
     existing = env.get('PYTHONPATH', '')
     env['PYTHONPATH'] = ':'.join(pythonpath_dirs + ([existing] if existing 
else []))
 
-    if collect_timings:
-        # Run tests one at a time to collect accurate timing
-        all_output = []
-        total_tests = len(tests)
-        try:
-            for idx, test in enumerate(tests, 1):
-                test_name, duration, status, output = run_single_test(
-                    test, script_dir, sandbox, ats_bin, build_root, 
extra_args, env)
-                result.test_timings[test_name] = duration
-                all_output.append(output)
-
-                if status == "PASS":
-                    result.passed += 1
-                elif status == "SKIP":
-                    result.skipped += 1
-                else:
-                    result.failed += 1
-                    result.failed_tests.append(test_name)
+    # Keep all tests in one autest process so its shared port queue is not
+    # reset between tests. This is both faster and avoids reusing ports that a
+    # recently completed test may still hold.
+    cmd = [
+        'uv',
+        'run',
+        'autest',
+        'run',
+        '--directory',
+        '${CMAKE_GOLD_DIR}',
+        '--ats-bin',
+        ats_bin,
+        '--proxy-verifier-bin',
+        '${PROXY_VERIFIER_PATH}',
+        '--build-root',
+        build_root,
+        '--sandbox',
+        str(sandbox),
+        '--filters',
+    ]
+    cmd.extend(f'/{test}' for test in tests)
+    cmd.extend(extra_args)
 
-                timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
-                # Fixed-width format: date time status duration worker 
progress test_name
-                print(
-                    f"{timestamp} {status:4s} {duration:6.1f}s 
Worker:{worker_id:2d} {idx:2d}/{total_tests:2d} {test}", flush=True)
-        except KeyboardInterrupt:
-            result.return_code = 130
+    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+    print(f"{timestamp} Worker:{worker_id:2d} Starting batch of {len(tests)} 
tests (port offset {port_offset})", flush=True)
+    if verbose:
+        print(
+            f"             Worker:{worker_id:2d} Tests: {', '.join(tests[:5])}"
+            f"{'...' if len(tests) > 5 else ''}",
+            flush=True)
 
-        result.output = "\n".join(all_output)
-        if result.return_code != 130:
-            result.return_code = 0 if result.failed == 0 else 1
-    else:
-        # Run all tests in batch (faster but no per-test timing)
-        cmd = [
-            'uv',
-            'run',
-            'autest',
-            'run',
-            '--directory',
-            '${CMAKE_GOLD_DIR}',
-            '--ats-bin',
-            ats_bin,
-            '--proxy-verifier-bin',
-            '${PROXY_VERIFIER_PATH}',
-            '--build-root',
-            build_root,
-            '--sandbox',
-            str(sandbox),
-        ]
-
-        # Add test filters
-        cmd.append('--filters')
-        cmd.extend(tests)
-
-        # Add any extra arguments
-        cmd.extend(extra_args)
-
-        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
-        print(f"{timestamp} Worker:{worker_id:2d} Starting batch of 
{len(tests)} tests (port offset {port_offset})", flush=True)
-        if verbose:
-            print(
-                f"             Worker:{worker_id:2d} Tests: {', 
'.join(tests[:5])}"
-                f"{'...' if len(tests) > 5 else ''}",
-                flush=True)
+    try:
+        if verbose or collect_timings:
+            # Autest flushes each completed test line. Observe those lines to
+            # collect timings without changing how autest executes the batch.
+            proc = subprocess.Popen(
+                cmd,
+                cwd=script_dir,
+                stdout=subprocess.PIPE,
+                stderr=subprocess.STDOUT,
+                text=True,
+                env=env,
+            )
+            output_lines = []
+            last_completion = time.monotonic()
+            completed_count = 0
+            pending_test = None
+            try:
+                for line in proc.stdout:

Review Comment:
   Fixed in 483ffc8c28. Worker stdout is now read into a queue by a daemon 
reader while the worker enforces a 600-second deadline between completed tests. 
On expiry it terminates and, if needed, kills the child and records a TIMEOUT 
diagnostic. I also exercised the timeout path with a reduced deadline and ran a 
two-worker collect-timings AuTest successfully.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to