forked from espressif/esp-idf
Merge branch 'feature/add_windows_pytest' into 'master'
Tools: Add pytest build system on Windows runner Closes IDF-7691, IDF-8214, and IDF-1193 See merge request espressif/esp-idf!26603
This commit is contained in:
@ -550,6 +550,38 @@ pytest_build_system_macos:
|
||||
reports:
|
||||
junit: XUNIT_RESULT.xml
|
||||
|
||||
.test_build_system_template_win:
|
||||
stage: host_test
|
||||
variables:
|
||||
# Enable ccache for all build jobs. See configure_ci_environment.sh for more ccache related settings.
|
||||
IDF_CCACHE_ENABLE: "1"
|
||||
PYTHONPATH: "$PYTHONPATH;$IDF_PATH\\tools;$IDF_PATH\\tools\\esp_app_trace;$IDF_PATH\\components\\partition_table;$IDF_PATH\\tools\\ci\\python_packages"
|
||||
before_script: []
|
||||
after_script: []
|
||||
timeout: 4 hours
|
||||
script:
|
||||
- .\install.ps1 --enable-ci --enable-pytest
|
||||
- . .\export.ps1
|
||||
- python "${SUBMODULE_FETCH_TOOL}" -s "all"
|
||||
- cd ${IDF_PATH}\tools\test_build_system
|
||||
- pytest --junitxml=${CI_PROJECT_DIR}\XUNIT_RESULT.xml
|
||||
|
||||
pytest_build_system_win:
|
||||
extends:
|
||||
- .test_build_system_template_win
|
||||
- .rules:test:windows_pytest_build_system
|
||||
needs: []
|
||||
tags:
|
||||
- windows-target
|
||||
artifacts:
|
||||
paths:
|
||||
- XUNIT_RESULT.xml
|
||||
- test_build_system
|
||||
when: always
|
||||
expire_in: 2 days
|
||||
reports:
|
||||
junit: XUNIT_RESULT.xml
|
||||
|
||||
build_docker:
|
||||
extends:
|
||||
- .before_script:minimal
|
||||
|
@ -175,6 +175,12 @@
|
||||
patterns:
|
||||
- submodule
|
||||
|
||||
"test:windows_pytest_build_system":
|
||||
labels:
|
||||
- windows
|
||||
specific_rules:
|
||||
- if-schedule-test-build-system-windows
|
||||
|
||||
#################################
|
||||
# Triggered Only By Labels Jobs #
|
||||
#################################
|
||||
|
@ -351,6 +351,9 @@
|
||||
.if-schedule: &if-schedule
|
||||
if: '$CI_PIPELINE_SOURCE == "schedule"'
|
||||
|
||||
.if-schedule-test-build-system-windows: &if-schedule-test-build-system-windows
|
||||
if: '$CI_PIPELINE_SOURCE == "schedule" && $SCHEDULED_BUILD_SYSTEM_TEST_WIN == "true"'
|
||||
|
||||
.if-trigger: &if-trigger
|
||||
if: '$CI_PIPELINE_SOURCE == "trigger"'
|
||||
|
||||
@ -562,6 +565,9 @@
|
||||
.if-label-target_test: &if-label-target_test
|
||||
if: '$BOT_LABEL_TARGET_TEST || $CI_MERGE_REQUEST_LABELS =~ /^(?:[^,\n\r]+,)*target_test(?:,[^,\n\r]+)*$/i'
|
||||
|
||||
.if-label-windows: &if-label-windows
|
||||
if: '$BOT_LABEL_WINDOWS || $CI_MERGE_REQUEST_LABELS =~ /^(?:[^,\n\r]+,)*windows(?:,[^,\n\r]+)*$/i'
|
||||
|
||||
.rules:build:
|
||||
rules:
|
||||
- <<: *if-revert-branch
|
||||
@ -2575,3 +2581,13 @@
|
||||
- <<: *if-label-submodule
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-submodule
|
||||
|
||||
.rules:test:windows_pytest_build_system:
|
||||
rules:
|
||||
- <<: *if-revert-branch
|
||||
when: never
|
||||
- <<: *if-protected
|
||||
- <<: *if-label-build-only
|
||||
when: never
|
||||
- <<: *if-schedule-test-build-system-windows
|
||||
- <<: *if-label-windows
|
||||
|
@ -4,6 +4,7 @@ import argparse
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import tarfile
|
||||
import tempfile
|
||||
import time
|
||||
@ -230,9 +231,19 @@ class Gitlab(object):
|
||||
|
||||
@staticmethod
|
||||
def decompress_archive(path: str, destination: str) -> str:
|
||||
full_destination = os.path.abspath(destination)
|
||||
# By default max path lenght is set to 260 characters
|
||||
# Prefix `\\?\` extends it to 32,767 characters
|
||||
if sys.platform == 'win32':
|
||||
full_destination = '\\\\?\\' + full_destination
|
||||
|
||||
try:
|
||||
with tarfile.open(path, 'r') as archive_file:
|
||||
root_name = archive_file.getnames()[0]
|
||||
archive_file.extractall(destination)
|
||||
archive_file.extractall(full_destination)
|
||||
except tarfile.TarError as e:
|
||||
logging.error(f'Error while decompressing archive {path}')
|
||||
raise e
|
||||
|
||||
return os.path.join(os.path.realpath(destination), root_name)
|
||||
|
||||
|
@ -28,7 +28,7 @@ def test_bootloader_custom_overrides_original(test_app_copy: Path, idf_py: IdfPy
|
||||
shutil.copytree(idf_path / 'components' / 'esp_bootloader_format', test_app_copy / 'components' / 'esp_bootloader_format')
|
||||
idf_py('bootloader')
|
||||
assert file_contains(test_app_copy / 'build' / 'bootloader' / 'compile_commands.json',
|
||||
str(test_app_copy / 'components' / 'bootloader' / 'subproject' / 'main' / 'bootloader_start.c'))
|
||||
(test_app_copy / 'components' / 'bootloader' / 'subproject' / 'main' / 'bootloader_start.c'))
|
||||
|
||||
|
||||
def test_bootloader_custom_ignores_extra_component(test_app_copy: Path, idf_py: IdfPyFunc, default_idf_env: EnvDict) -> None:
|
||||
|
@ -7,7 +7,7 @@ import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import typing
|
||||
from pathlib import Path
|
||||
from pathlib import Path, WindowsPath
|
||||
from typing import Pattern, Union
|
||||
|
||||
try:
|
||||
@ -137,7 +137,7 @@ def run_cmake_and_build(*cmake_args: str, env: typing.Optional[EnvDict] = None)
|
||||
run_cmake('--build', '.')
|
||||
|
||||
|
||||
def file_contains(filename: Union[str, Path], what: Union[str, Pattern]) -> bool:
|
||||
def file_contains(filename: Union[str, Path], what: Union[Union[str, Path], Pattern]) -> bool:
|
||||
"""
|
||||
Returns true if file contains required object
|
||||
:param filename: path to file where lookup is executed
|
||||
@ -145,10 +145,16 @@ def file_contains(filename: Union[str, Path], what: Union[str, Pattern]) -> bool
|
||||
"""
|
||||
with open(filename, 'r', encoding='utf-8') as f:
|
||||
data = f.read()
|
||||
if isinstance(what, str):
|
||||
return what in data
|
||||
else:
|
||||
if isinstance(what, Pattern):
|
||||
return re.search(what, data) is not None
|
||||
else:
|
||||
what_str = str(what)
|
||||
# In case of windows path, try both single-slash `\` and double-slash '\\' paths
|
||||
if isinstance(what, WindowsPath):
|
||||
what_double_slash = what_str.replace('\\', '\\\\')
|
||||
return what_str in data or what_double_slash in data
|
||||
|
||||
return what_str in data
|
||||
|
||||
|
||||
def bin_file_contains(filename: Union[str, Path], what: bytearray) -> bool:
|
||||
|
@ -4,12 +4,14 @@ import logging
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from test_build_system_helpers import EnvDict, IdfPyFunc, append_to_file, file_contains, run_cmake, run_cmake_and_build
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform == 'win32', reason='Failing on Windows runner. TODO')
|
||||
def test_build_custom_cmake_project(test_app_copy: Path) -> None:
|
||||
for target in ['esp32', 'esp32s3', 'esp32c6', 'esp32h2']:
|
||||
logging.info(f'Test build ESP-IDF as a library to a custom CMake projects for {target}')
|
||||
@ -50,6 +52,7 @@ def test_build_cmake_library_psram_strategies(idf_py: IdfPyFunc, test_app_copy:
|
||||
(test_app_copy / 'sdkconfig').unlink()
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform == 'win32', reason='Failing on Windows runner. TODO')
|
||||
@pytest.mark.usefixtures('test_app_copy')
|
||||
@pytest.mark.usefixtures('idf_copy')
|
||||
def test_defaults_for_unspecified_idf_build_process_args(default_idf_env: EnvDict) -> None:
|
||||
|
@ -207,6 +207,7 @@ def test_fallback_to_build_system_target(idf_py: IdfPyFunc, test_app_copy: Path)
|
||||
assert msg in ret.stdout, 'Custom target did not produce expected output'
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform == 'win32', reason='Failing on Windows runner. TODO')
|
||||
def test_create_component_and_project_plus_build(idf_copy: Path) -> None:
|
||||
logging.info('Create project and component using idf.py and build it')
|
||||
run_idf_py('-C', 'projects', 'create-project', 'temp_test_project', workdir=idf_copy)
|
||||
|
@ -4,12 +4,14 @@
|
||||
import json
|
||||
import logging
|
||||
import shutil
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from test_build_system_helpers import EnvDict, IdfPyFunc, append_to_file, replace_in_file
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform == 'win32', reason='Failing on Windows runner. TODO')
|
||||
def test_component_extra_dirs(idf_py: IdfPyFunc, test_app_copy: Path) -> None:
|
||||
logging.info('Setting EXTRA_COMPONENT_DIRS works')
|
||||
shutil.move(test_app_copy / 'main', test_app_copy / 'different_main' / 'main')
|
||||
@ -42,6 +44,7 @@ def test_component_can_not_be_empty_dir(idf_py: IdfPyFunc, test_app_copy: Path)
|
||||
assert str(empty_component_dir) not in data.get('build_component_paths')
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform == 'win32', reason='Failing on Windows runner. TODO')
|
||||
def test_component_subdirs_not_added_to_component_dirs(idf_py: IdfPyFunc, test_app_copy: Path) -> None:
|
||||
logging.info('If a component directory is added to COMPONENT_DIRS, its subdirectories are not added')
|
||||
(test_app_copy / 'main' / 'test').mkdir(parents=True)
|
||||
@ -52,6 +55,7 @@ def test_component_subdirs_not_added_to_component_dirs(idf_py: IdfPyFunc, test_a
|
||||
assert str(test_app_copy / 'main') in data.get('build_component_paths')
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform == 'win32', reason='Failing on Windows runner. TODO')
|
||||
def test_component_sibling_dirs_not_added_to_component_dirs(idf_py: IdfPyFunc, test_app_copy: Path) -> None:
|
||||
logging.info('If a component directory is added to COMPONENT_DIRS, its sibling directories are not added')
|
||||
mycomponents_subdir = (test_app_copy / 'mycomponents')
|
||||
@ -76,6 +80,7 @@ def test_component_sibling_dirs_not_added_to_component_dirs(idf_py: IdfPyFunc, t
|
||||
assert str(mycomponents_subdir / 'mycomponent') in data.get('build_component_paths')
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform == 'win32', reason='Failing on Windows runner. TODO')
|
||||
def test_component_properties_are_set(idf_py: IdfPyFunc, test_app_copy: Path) -> None:
|
||||
logging.info('Component properties are set')
|
||||
append_to_file(test_app_copy / 'CMakeLists.txt', '\n'.join(['',
|
||||
@ -85,6 +90,7 @@ def test_component_properties_are_set(idf_py: IdfPyFunc, test_app_copy: Path) ->
|
||||
assert 'SRCS:{}'.format(test_app_copy / 'main' / 'build_test_app.c') in ret.stdout, 'Component properties should be set'
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform == 'win32', reason='Failing on Windows runner. TODO')
|
||||
def test_component_overriden_dir(idf_py: IdfPyFunc, test_app_copy: Path, default_idf_env: EnvDict) -> None:
|
||||
logging.info('Getting component overriden dir')
|
||||
(test_app_copy / 'components' / 'hal').mkdir(parents=True)
|
||||
@ -104,6 +110,7 @@ def test_component_overriden_dir(idf_py: IdfPyFunc, test_app_copy: Path, default
|
||||
assert 'kconfig:{}'.format(idf_path / 'components' / 'hal') in ret.stdout, 'Failed to verify original `main` directory'
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform == 'win32', reason='Failing on Windows runner. TODO')
|
||||
def test_components_prioritizer_over_extra_components_dir(idf_py: IdfPyFunc, test_app_copy: Path) -> None:
|
||||
logging.info('Project components prioritized over EXTRA_COMPONENT_DIRS')
|
||||
(test_app_copy / 'extra_dir' / 'my_component').mkdir(parents=True)
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
import logging
|
||||
import shutil
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import List, Optional
|
||||
|
||||
@ -31,6 +32,7 @@ def test_target_from_environment_cmake(default_idf_env: EnvDict) -> None:
|
||||
assert file_contains('build/CMakeCache.txt', 'IDF_TARGET:STRING={}'.format(ESP32S2_TARGET))
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform == 'win32', reason='Failing on Windows runner. TODO')
|
||||
def test_target_from_environment_idf_py(idf_py: IdfPyFunc, default_idf_env: EnvDict, test_app_copy: Path) -> None:
|
||||
def reconfigure_and_check_return_values(errmsg: str, opts: Optional[List[str]] = None) -> None:
|
||||
opts = opts or []
|
||||
@ -72,6 +74,7 @@ def test_target_from_environment_idf_py(idf_py: IdfPyFunc, default_idf_env: EnvD
|
||||
['-D', 'IDF_TARGET={}'.format(ESP32_TARGET)])
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform == 'win32', reason='Failing on Windows runner. TODO')
|
||||
def test_target_consistency_cmake(default_idf_env: EnvDict, test_app_copy: Path) -> None:
|
||||
def reconfigure_and_check_return_values(errmsg: str, opts: Optional[List[str]] = None) -> None:
|
||||
opts = opts or []
|
||||
|
@ -20,6 +20,7 @@ def clean_app_dir(app_path: Path) -> None:
|
||||
shutil.rmtree(app_path / 'build', ignore_errors=True)
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform == 'win32', reason='Failing on Windows runner. TODO')
|
||||
@pytest.mark.idf_copy('esp idf with spaces')
|
||||
def test_spaces_bundle1(idf_copy: Path) -> None:
|
||||
logging.info('Running test spaces bundle 1')
|
||||
@ -33,6 +34,7 @@ def test_spaces_bundle1(idf_copy: Path) -> None:
|
||||
run_idf_py('build', workdir=(idf_copy / 'examples' / 'storage' / 'spiffsgen'))
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform == 'win32', reason='Failing on Windows runner. TODO')
|
||||
@pytest.mark.idf_copy('esp idf with spaces')
|
||||
def test_spaces_bundle2(idf_copy: Path) -> None:
|
||||
logging.info('Running test spaces bundle 2')
|
||||
@ -48,6 +50,7 @@ def test_spaces_bundle2(idf_copy: Path) -> None:
|
||||
run_idf_py('uf2', workdir=hello_world_app_path)
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform == 'win32', reason='Failing on Windows runner. TODO')
|
||||
@pytest.mark.idf_copy('esp idf with spaces')
|
||||
def test_spaces_bundle3(idf_copy: Path) -> None:
|
||||
logging.info('Running test spaces bundle 3')
|
||||
@ -86,6 +89,7 @@ def test_install_export_unix(idf_copy: Path) -> None:
|
||||
subprocess.check_call(export_cmd, env=env, shell=True, cwd=idf_copy, executable='/bin/bash')
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform == 'win32', reason='Failing on Windows runner. TODO')
|
||||
@pytest.mark.skipif(sys.platform != 'win32', reason='Windows test')
|
||||
@pytest.mark.idf_copy('esp idf with spaces')
|
||||
def test_install_export_win(idf_copy: Path) -> None:
|
||||
|
Reference in New Issue
Block a user