utils.py 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. # SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
  2. # SPDX-License-Identifier: Apache-2.0
  3. import logging
  4. import os
  5. import typing as t
  6. from xml.etree import ElementTree as ET
  7. from .constants import TARGET_MARKERS
  8. def format_case_id(target: t.Optional[str], config: t.Optional[str], case: str, is_qemu: bool = False, params: t.Optional[dict] = None) -> str:
  9. parts = []
  10. if target:
  11. parts.append((str(target) + '_qemu') if is_qemu else str(target))
  12. if config:
  13. parts.append(str(config))
  14. parts.append(case)
  15. if params:
  16. parts.append(str(params))
  17. return '.'.join(parts)
  18. def get_target_marker_from_expr(markexpr: str) -> str:
  19. candidates = set()
  20. # we use `-m "esp32 and generic"` in our CI to filter the test cases
  21. # this doesn't cover all use cases, but fit what we do in CI.
  22. for marker in markexpr.split('and'):
  23. marker = marker.strip()
  24. if marker in TARGET_MARKERS:
  25. candidates.add(marker)
  26. if len(candidates) > 1:
  27. raise ValueError(f'Specified more than one target markers: {candidates}. Please specify no more than one.')
  28. elif len(candidates) == 1:
  29. return candidates.pop()
  30. else:
  31. raise ValueError('Please specify one target marker via "--target [TARGET]" or via "-m [TARGET]"')
  32. def merge_junit_files(junit_files: t.List[str], target_path: str) -> None:
  33. if len(junit_files) <= 1:
  34. return
  35. merged_testsuite: ET.Element = ET.Element('testsuite')
  36. testcases: t.Dict[str, ET.Element] = {}
  37. for junit in junit_files:
  38. logging.info(f'Merging {junit} to {target_path}')
  39. tree: ET.ElementTree = ET.parse(junit)
  40. testsuite: ET.Element = tree.getroot()
  41. for testcase in testsuite.findall('testcase'):
  42. name: str = testcase.get('name') if testcase.get('name') else '' # type: ignore
  43. if name not in testcases:
  44. testcases[name] = testcase
  45. merged_testsuite.append(testcase)
  46. continue
  47. existing_testcase = testcases[name]
  48. for element_name in ['failure', 'error']:
  49. for element in testcase.findall(element_name):
  50. existing_element = existing_testcase.find(element_name)
  51. if existing_element is None:
  52. existing_testcase.append(element)
  53. else:
  54. existing_element.attrib.setdefault('message', '') # type: ignore
  55. existing_element.attrib['message'] += '. ' + element.get('message', '') # type: ignore
  56. os.remove(junit)
  57. merged_testsuite.set('tests', str(len(merged_testsuite.findall('testcase'))))
  58. merged_testsuite.set('failures', str(len(merged_testsuite.findall('.//testcase/failure'))))
  59. merged_testsuite.set('errors', str(len(merged_testsuite.findall('.//testcase/error'))))
  60. merged_testsuite.set('skipped', str(len(merged_testsuite.findall('.//testcase/skipped'))))
  61. with open(target_path, 'wb') as fw:
  62. fw.write(ET.tostring(merged_testsuite))