diff --git a/azure-pipelines.yml b/azure-pipelines.yml index accd67ee..0f2621d8 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -19,39 +19,54 @@ jobs: - job: tests strategy: matrix: - linux_311: + linux_313: imageName: "ubuntu-latest" - pythonVersion: "3.11" + pythonVersion: "3.13" testSelect: "native" - android_311: + android_313: imageName: "ubuntu-latest" - pythonVersion: "3.11" + pythonVersion: "3.13" testSelect: "android" - macos_311: + macos_313: imageName: "macos-latest" - pythonVersion: "3.11" + pythonVersion: "3.13" testSelect: "native" - ios_311: + ios_313: imageName: "macos-14" # See https://github.com/actions/runner-images/issues/12777 - pythonVersion: "3.11" + pythonVersion: "3.13" testSelect: "ios" - android_macos_311: + android_macos_313: imageName: "macos-latest" - pythonVersion: "3.11" + pythonVersion: "3.13" testSelect: "android" - windows_311: + windows_313: imageName: "windows-latest" - pythonVersion: "3.11" + pythonVersion: "3.13" testSelect: "native" timeoutInMinutes: 180 pool: vmImage: $(imageName) + variables: + # Relocate cibuildwheel's download cache (interpreters) and the per-worker + # test pip caches (which live under it) to a stable, cacheable path. + CIBW_CACHE_PATH: $(Pipeline.Workspace)/.cibw-cache steps: - task: UsePythonVersion@0 inputs: versionSpec: $(pythonVersion) + - task: Cache@2 + displayName: 'Cache cibuildwheel downloads' + inputs: + # build-platforms.toml carries the interpreter pins; bump the version + # prefix to force a cold cache. restoreKeys lets a stale cache still seed + # a new run (cibuildwheel re-downloads only what's missing). + key: 'cibw-cache | v1 | "$(imageName)" | "$(testSelect)" | cibuildwheel/resources/build-platforms.toml' + restoreKeys: | + cibw-cache | v1 | "$(imageName)" | "$(testSelect)" + path: $(CIBW_CACHE_PATH) + - task: JavaToolInstaller@0 condition: and(eq(variables['testSelect'], 'android'), eq(variables['Agent.OS'], 'Linux')) inputs: diff --git a/test/test_0_basic.py b/test/test_0_basic.py index 8c1d9b75..08c44905 100644 --- a/test/test_0_basic.py +++ b/test/test_0_basic.py @@ -35,6 +35,7 @@ def test_dummy_serial() -> None: """ +@pytest.mark.flaky(reruns=2, reruns_delay=5) def test( tmp_path: Path, build_frontend_env: dict[str, str], capfd: pytest.CaptureFixture[str] ) -> None: diff --git a/test/test_ios.py b/test/test_ios.py index d36437d9..4ee4b3e1 100644 --- a/test/test_ios.py +++ b/test/test_ios.py @@ -48,7 +48,7 @@ def skip_if_ios_testing_not_supported() -> None: # which is guaranteed to run single-process. # This can also fail the first time sometimes. @pytest.mark.serial -@pytest.mark.flaky(reruns=2) +@pytest.mark.flaky(reruns=1) @pytest.mark.parametrize( "build_config", [ @@ -173,7 +173,7 @@ def test_ios_testing_with_placeholder(tmp_path: Path, capfd: pytest.CaptureFixtu @pytest.mark.serial -@pytest.mark.flaky(reruns=2) +@pytest.mark.flaky(reruns=1) def test_ios_test_command_short_circuit(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None: skip_if_ios_testing_not_supported() diff --git a/unit_test/oci_container_test.py b/unit_test/oci_container_test.py index 76f03111..8b94187c 100644 --- a/unit_test/oci_container_test.py +++ b/unit_test/oci_container_test.py @@ -546,6 +546,7 @@ def test_disable_host_mount( container.call(["cat", host_mount_path], capture_output=True) +@pytest.mark.flaky(reruns=2, reruns_delay=5) @pytest.mark.parametrize("platform", list(OCIPlatform)) def test_local_image( container_engine: OCIContainerEngineConfig, platform: OCIPlatform, tmp_path: Path @@ -587,6 +588,7 @@ def test_local_image( assert container._get_platform_args() == expected_platform_args +@pytest.mark.flaky(reruns=2, reruns_delay=5) def test_enter_error(container_engine: OCIContainerEngineConfig, tmp_path: Path) -> None: remote_image = "debian:trixie-slim" platform = DEFAULT_OCI_PLATFORM @@ -745,6 +747,7 @@ def test_exit_kills_process_on_shutdown_timeout(monkeypatch: pytest.MonkeyPatch) assert bash_stdout.closed +@pytest.mark.flaky(reruns=2, reruns_delay=5) @pytest.mark.parametrize("platform", list(OCIPlatform)) def test_multiarch_image(container_engine: OCIContainerEngineConfig, platform: OCIPlatform) -> None: if detect_ci_provider() == CIProvider.travis_ci and DEFAULT_OCI_PLATFORM not in {