mirror of
https://github.com/espressif/esp-idf.git
synced 2025-10-02 01:50:58 +02:00
ci(test): Improve test failures on Windows
Tests are made cancellable and to print STDOUT and STDERR upon failures.
This commit is contained in:
@@ -6,7 +6,9 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
import unittest
|
import unittest
|
||||||
|
import warnings
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from subprocess import TimeoutExpired
|
||||||
from subprocess import run
|
from subprocess import run
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
@@ -27,6 +29,18 @@ except ImportError:
|
|||||||
from idf_py_actions.tools import generate_hints
|
from idf_py_actions.tools import generate_hints
|
||||||
|
|
||||||
|
|
||||||
|
def safe_cleanup_tmpdir(tmpdir: tempfile.TemporaryDirectory) -> None:
|
||||||
|
"""Safely cleanup temporary directory, handling specific errors on Windows."""
|
||||||
|
try:
|
||||||
|
tmpdir.cleanup()
|
||||||
|
except (PermissionError, NotADirectoryError):
|
||||||
|
warnings.warn(
|
||||||
|
f'Failed to cleanup temporary directory {tmpdir.name}. '
|
||||||
|
'This is common on Windows when files are still in use.',
|
||||||
|
UserWarning,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestHintsMassages(unittest.TestCase):
|
class TestHintsMassages(unittest.TestCase):
|
||||||
def setUp(self) -> None:
|
def setUp(self) -> None:
|
||||||
self.tmpdir = tempfile.TemporaryDirectory()
|
self.tmpdir = tempfile.TemporaryDirectory()
|
||||||
@@ -43,14 +57,28 @@ class TestHintsMassages(unittest.TestCase):
|
|||||||
self.assertEqual(generated_hint, hint)
|
self.assertEqual(generated_hint, hint)
|
||||||
|
|
||||||
def tearDown(self) -> None:
|
def tearDown(self) -> None:
|
||||||
self.tmpdir.cleanup()
|
safe_cleanup_tmpdir(self.tmpdir)
|
||||||
|
|
||||||
|
|
||||||
def run_idf(args: list[str], cwd: Path) -> str:
|
def run_idf(args: list[str], cwd: Path) -> str:
|
||||||
# Simple helper to run idf command and return it's stdout.
|
# Simple helper to run idf command and return it's stdout.
|
||||||
cmd = [sys.executable, os.path.join(os.environ['IDF_PATH'], 'tools', 'idf.py')]
|
cmd = [sys.executable, os.path.join(os.environ['IDF_PATH'], 'tools', 'idf.py')]
|
||||||
proc = run(cmd + args, capture_output=True, cwd=cwd, text=True)
|
try:
|
||||||
return str(proc.stdout + proc.stderr)
|
proc = run(cmd + args, capture_output=True, cwd=cwd, text=True, timeout=10 * 60)
|
||||||
|
return str(proc.stdout + proc.stderr)
|
||||||
|
except TimeoutExpired as e:
|
||||||
|
# Print captured output on timeout to help with debugging
|
||||||
|
print(f'\n{"=" * 80}')
|
||||||
|
print(f'TEST TIMEOUT: idf.py {" ".join(args)} timed out')
|
||||||
|
print(f'{"=" * 80}')
|
||||||
|
if e.stdout:
|
||||||
|
print('CAPTURED STDOUT:')
|
||||||
|
print(e.stdout)
|
||||||
|
if e.stderr:
|
||||||
|
print('CAPTURED STDERR:')
|
||||||
|
print(e.stderr)
|
||||||
|
print(f'{"=" * 80}')
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
class TestHintModuleComponentRequirements(unittest.TestCase):
|
class TestHintModuleComponentRequirements(unittest.TestCase):
|
||||||
@@ -114,7 +142,7 @@ class TestHintModuleComponentRequirements(unittest.TestCase):
|
|||||||
self.assertIn('To fix this, move esp_psram from PRIV_REQUIRES into REQUIRES', output)
|
self.assertIn('To fix this, move esp_psram from PRIV_REQUIRES into REQUIRES', output)
|
||||||
|
|
||||||
def tearDown(self) -> None:
|
def tearDown(self) -> None:
|
||||||
self.tmpdir.cleanup()
|
safe_cleanup_tmpdir(self.tmpdir)
|
||||||
|
|
||||||
|
|
||||||
class TestNestedModuleComponentRequirements(unittest.TestCase):
|
class TestNestedModuleComponentRequirements(unittest.TestCase):
|
||||||
@@ -161,7 +189,7 @@ class TestNestedModuleComponentRequirements(unittest.TestCase):
|
|||||||
self.assertIn('To fix this, add esp_timer to PRIV_REQUIRES list of idf_component_register call', output)
|
self.assertIn('To fix this, add esp_timer to PRIV_REQUIRES list of idf_component_register call', output)
|
||||||
|
|
||||||
def tearDown(self) -> None:
|
def tearDown(self) -> None:
|
||||||
self.tmpdir.cleanup()
|
safe_cleanup_tmpdir(self.tmpdir)
|
||||||
|
|
||||||
|
|
||||||
class TestTrimmedModuleComponentRequirements(unittest.TestCase):
|
class TestTrimmedModuleComponentRequirements(unittest.TestCase):
|
||||||
@@ -193,7 +221,7 @@ class TestTrimmedModuleComponentRequirements(unittest.TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def tearDown(self) -> None:
|
def tearDown(self) -> None:
|
||||||
self.tmpdir.cleanup()
|
safe_cleanup_tmpdir(self.tmpdir)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
Reference in New Issue
Block a user