Skip to content

Commit 52bc5cf

Browse files
authored
Investigate test flakes (#832)
1 parent fd49c4e commit 52bc5cf

14 files changed

+91
-33
lines changed

Diff for: .github/workflows/ci.yml

+14-2
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,16 @@ on:
99
jobs:
1010
# Build and test the project
1111
build-lint-test:
12+
timeout-minutes: 30
1213
strategy:
1314
fail-fast: false
1415
matrix:
1516
python: ["3.9", "3.13"]
1617
os: [ubuntu-latest, ubuntu-arm, macos-intel, macos-arm, windows-latest]
1718
include:
1819
# On 3.9 there is a problem with import errors caused by pytests' loader that surface due
19-
# to a bug in CPython, so we avoid using the assert rewriter.
20+
# to a bug in CPython (https://github.com/python/cpython/issues/91351), so we avoid using
21+
# the assert rewriter.
2022
- python: "3.9"
2123
pytestExtraArgs: "--assert=plain"
2224
- os: ubuntu-latest
@@ -31,6 +33,12 @@ jobs:
3133
runsOn: ubuntu-24.04-arm64-2-core
3234
- os: macos-intel
3335
runsOn: macos-13
36+
# On 3.13.3 there is some issue with macOS intel where it hangs after pytest with some
37+
# test that may have a worker that cannot properly shutdown, but it does not occur on
38+
# other versions, platforms, etc. See https://github.com/temporalio/sdk-python/issues/834.
39+
- os: macos-intel
40+
python: "3.13"
41+
pythonOverride: "3.13.2"
3442
- os: macos-arm
3543
runsOn: macos-latest
3644
runs-on: ${{ matrix.runsOn || matrix.os }}
@@ -44,7 +52,7 @@ jobs:
4452
workspaces: temporalio/bridge -> target
4553
- uses: actions/setup-python@v5
4654
with:
47-
python-version: ${{ matrix.python }}
55+
python-version: ${{ matrix.pythonOverride || matrix.python }}
4856
- uses: arduino/setup-protoc@v3
4957
with:
5058
# TODO(cretz): Can upgrade proto when https://github.com/arduino/setup-protoc/issues/99 fixed
@@ -59,12 +67,15 @@ jobs:
5967
- run: poe build-develop
6068
- run: mkdir junit-xml
6169
- run: poe test ${{matrix.pytestExtraArgs}} -s --junit-xml=junit-xml/${{ matrix.python }}--${{ matrix.os }}.xml
70+
timeout-minutes: 10
6271
# Time skipping doesn't yet support ARM
6372
- if: ${{ !endsWith(matrix.os, '-arm') }}
6473
run: poe test ${{matrix.pytestExtraArgs}} -s --workflow-environment time-skipping --junit-xml=junit-xml/${{ matrix.python }}--${{ matrix.os }}--time-skipping.xml
74+
timeout-minutes: 10
6575
# Check cloud if proper target and not on fork
6676
- if: ${{ matrix.cloudTestTarget && (github.event.pull_request.head.repo.full_name == '' || github.event.pull_request.head.repo.full_name == 'temporalio/sdk-python') }}
6777
run: poe test ${{matrix.pytestExtraArgs}} -s -k test_cloud_client --junit-xml=junit-xml/${{ matrix.python }}--${{ matrix.os }}--cloud.xml
78+
timeout-minutes: 10
6879
env:
6980
TEMPORAL_CLIENT_CLOUD_API_KEY: ${{ secrets.TEMPORAL_CLIENT_CLOUD_API_KEY }}
7081
TEMPORAL_CLIENT_CLOUD_API_VERSION: 2024-05-13-00
@@ -94,6 +105,7 @@ jobs:
94105
poe format
95106
[[ -z $(git status --porcelain temporalio) ]] || (git diff temporalio; echo "Protos changed"; exit 1)
96107
poe test -s
108+
timeout-minutes: 10
97109

98110
# Do docs stuff (only on one host)
99111
- name: Build API docs

Diff for: tests/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# TODO: Change back to "default" after next CLI release
2+
DEV_SERVER_DOWNLOAD_VERSION = "v1.3.1-persistence-fix.0"

Diff for: tests/conftest.py

+8-7
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import pytest
77
import pytest_asyncio
88

9+
from . import DEV_SERVER_DOWNLOAD_VERSION
10+
911
# If there is an integration test environment variable set, we must remove the
1012
# first path from the sys.path so we can import the wheel instead
1113
if os.getenv("TEMPORAL_INTEGRATION_TEST"):
@@ -114,8 +116,7 @@ async def env(env_type: str) -> AsyncGenerator[WorkflowEnvironment, None]:
114116
"--dynamic-config-value",
115117
"system.enableDeploymentVersions=true",
116118
],
117-
# TODO: Remove after next CLI release
118-
dev_server_download_version="v1.3.1-priority.0",
119+
dev_server_download_version=DEV_SERVER_DOWNLOAD_VERSION,
119120
)
120121
elif env_type == "time-skipping":
121122
env = await WorkflowEnvironment.start_time_skipping()
@@ -139,11 +140,11 @@ async def worker(
139140
await worker.close()
140141

141142

142-
# There is an issue on Windows 3.9 tests in GitHub actions where even though all
143-
# tests pass, an unclear outer area is killing the process with a bad exit code.
144-
# This windows-only hook forcefully kills the process as success when the exit
145-
# code from pytest is a success.
146-
if sys.version_info < (3, 10) and sys.platform == "win32":
143+
# There is an issue on 3.9 tests in GitHub actions where even though all tests
144+
# pass, an unclear outer area is killing the process with a bad exit code. This
145+
# hook forcefully kills the process as success when the exit code from pytest
146+
# is a success.
147+
if sys.version_info < (3, 10):
147148

148149
@pytest.hookimpl(hookwrapper=True, trylast=True)
149150
def pytest_cmdline_main(config):

Diff for: tests/contrib/test_opentelemetry.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
from datetime import timedelta
88
from typing import Iterable, List, Optional
99

10-
import pytest
1110
from opentelemetry.sdk.trace import ReadableSpan, TracerProvider
1211
from opentelemetry.sdk.trace.export import SimpleSpanProcessor
1312
from opentelemetry.sdk.trace.export.in_memory_span_exporter import InMemorySpanExporter
@@ -21,6 +20,11 @@
2120
from temporalio.testing import WorkflowEnvironment
2221
from temporalio.worker import UnsandboxedWorkflowRunner, Worker
2322

23+
# Passing through because Python 3.9 has an import bug at
24+
# https://github.com/python/cpython/issues/91351
25+
with workflow.unsafe.imports_passed_through():
26+
import pytest
27+
2428

2529
@dataclass
2630
class TracingActivityParam:

Diff for: tests/test_client.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
import google.protobuf.any_pb2
1010
import google.protobuf.message
11-
import pytest
1211
from google.protobuf import json_format
1312

1413
import temporalio.api.common.v1
@@ -106,6 +105,11 @@
106105
KSWorkflowParams,
107106
)
108107

108+
# Passing through because Python 3.9 has an import bug at
109+
# https://github.com/python/cpython/issues/91351
110+
with workflow.unsafe.imports_passed_through():
111+
import pytest
112+
109113

110114
async def test_start_id_reuse(
111115
client: Client, worker: ExternalWorker, env: WorkflowEnvironment

Diff for: tests/test_workflow.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22
import itertools
33
from typing import Sequence
44

5-
import pytest
6-
75
from temporalio import workflow
86
from temporalio.common import RawValue, VersioningBehavior
97

8+
# Passing through because Python 3.9 has an import bug at
9+
# https://github.com/python/cpython/issues/91351
10+
with workflow.unsafe.imports_passed_through():
11+
import pytest
12+
1013

1114
class GoodDefnBase:
1215
@workflow.run

Diff for: tests/testing/test_workflow.py

+8-3
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
from time import monotonic
77
from typing import Any, List, Optional, Union
88

9-
import pytest
10-
119
from temporalio import activity, workflow
1210
from temporalio.client import (
1311
Client,
@@ -31,8 +29,14 @@
3129
TimeoutType,
3230
)
3331
from temporalio.testing import WorkflowEnvironment
32+
from tests import DEV_SERVER_DOWNLOAD_VERSION
3433
from tests.helpers import new_worker
3534

35+
# Passing through because Python 3.9 has an import bug at
36+
# https://github.com/python/cpython/issues/91351
37+
with workflow.unsafe.imports_passed_through():
38+
import pytest
39+
3640

3741
@workflow.defn
3842
class ReallySlowWorkflow:
@@ -306,7 +310,8 @@ async def test_search_attributes_on_dev_server(
306310
float_attr,
307311
bool_attr,
308312
datetime_attr,
309-
]
313+
],
314+
dev_server_download_version=DEV_SERVER_DOWNLOAD_VERSION,
310315
) as env:
311316
handle = await env.client.start_workflow(
312317
"some-workflow",

Diff for: tests/worker/test_activity.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@
1515
from datetime import datetime, timedelta, timezone
1616
from typing import Any, Callable, List, NoReturn, Optional, Sequence, Type
1717

18-
import pytest
19-
2018
from temporalio import activity, workflow
2119
from temporalio.client import (
2220
AsyncActivityHandle,
@@ -48,6 +46,12 @@
4846
KSWorkflowParams,
4947
)
5048

49+
# Passing through because Python 3.9 has an import bug at
50+
# https://github.com/python/cpython/issues/91351
51+
with workflow.unsafe.imports_passed_through():
52+
import pytest
53+
54+
5155
_default_shared_state_manager = SharedStateManager.create_from_multiprocessing(
5256
multiprocessing.Manager()
5357
)

Diff for: tests/worker/test_interceptor.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
from datetime import timedelta
44
from typing import Any, Callable, List, NoReturn, Optional, Tuple, Type
55

6-
import pytest
7-
86
from temporalio import activity, workflow
97
from temporalio.client import Client, WorkflowUpdateFailedError
108
from temporalio.exceptions import ApplicationError
@@ -30,6 +28,11 @@
3028
WorkflowOutboundInterceptor,
3129
)
3230

31+
# Passing through because Python 3.9 has an import bug at
32+
# https://github.com/python/cpython/issues/91351
33+
with workflow.unsafe.imports_passed_through():
34+
import pytest
35+
3336
interceptor_traces: List[Tuple[str, Any]] = []
3437

3538

Diff for: tests/worker/test_replayer.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
from pathlib import Path
77
from typing import Any, Dict, Optional, Type
88

9-
import pytest
10-
119
from temporalio import activity, workflow
1210
from temporalio.client import Client, WorkflowFailureError, WorkflowHistory
1311
from temporalio.exceptions import ApplicationError
@@ -26,6 +24,11 @@
2624
SignalsActivitiesTimersUpdatesTracingWorkflow,
2725
)
2826

27+
# Passing through because Python 3.9 has an import bug at
28+
# https://github.com/python/cpython/issues/91351
29+
with workflow.unsafe.imports_passed_through():
30+
import pytest
31+
2932

3033
@activity.defn
3134
async def say_hello(name: str) -> str:

Diff for: tests/worker/test_update_with_start.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
from typing import Any, Iterator, Mapping, Optional
99
from unittest.mock import patch
1010

11-
import pytest
12-
1311
import temporalio.api.common.v1
1412
import temporalio.api.workflowservice.v1
1513
from temporalio import activity, workflow
@@ -33,6 +31,11 @@
3331
new_worker,
3432
)
3533

34+
# Passing through because Python 3.9 has an import bug at
35+
# https://github.com/python/cpython/issues/91351
36+
with workflow.unsafe.imports_passed_through():
37+
import pytest
38+
3639

3740
@activity.defn
3841
async def activity_called_by_update() -> None:

Diff for: tests/worker/test_worker.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
from datetime import timedelta
88
from typing import Any, Awaitable, Callable, Optional, Sequence
99

10-
import pytest
11-
1210
import temporalio.api.enums.v1
1311
import temporalio.worker._worker
1412
from temporalio import activity, workflow
@@ -45,6 +43,11 @@
4543
from temporalio.workflow import VersioningIntent
4644
from tests.helpers import assert_eventually, new_worker, worker_versioning_enabled
4745

46+
# Passing through because Python 3.9 has an import bug at
47+
# https://github.com/python/cpython/issues/91351
48+
with workflow.unsafe.imports_passed_through():
49+
import pytest
50+
4851

4952
def test_load_default_worker_binary_id():
5053
# Just run it twice and confirm it didn't change

Diff for: tests/worker/test_workflow.py

+12-5
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
)
3636
from urllib.request import urlopen
3737

38-
import pytest
3938
from google.protobuf.timestamp_pb2 import Timestamp
4039
from typing_extensions import Literal, Protocol, runtime_checkable
4140

@@ -111,6 +110,7 @@
111110
WorkflowInstanceDetails,
112111
WorkflowRunner,
113112
)
113+
from tests import DEV_SERVER_DOWNLOAD_VERSION
114114
from tests.helpers import (
115115
admitted_update_task,
116116
assert_eq_eventually,
@@ -127,6 +127,11 @@
127127
external_wait_cancel,
128128
)
129129

130+
# Passing through because Python 3.9 has an import bug at
131+
# https://github.com/python/cpython/issues/91351
132+
with workflow.unsafe.imports_passed_through():
133+
import pytest
134+
130135

131136
@workflow.defn
132137
class HelloWorkflow:
@@ -5083,7 +5088,9 @@ async def test_workflow_replace_worker_client(client: Client, env: WorkflowEnvir
50835088
# we will terminate both. We have to use a ticking workflow with only one
50845089
# poller to force a quick re-poll to recognize our client change quickly (as
50855090
# opposed to just waiting the minute for poll timeout).
5086-
async with await WorkflowEnvironment.start_local() as other_env:
5091+
async with await WorkflowEnvironment.start_local(
5092+
dev_server_download_version=DEV_SERVER_DOWNLOAD_VERSION
5093+
) as other_env:
50875094
# Start both workflows on different servers
50885095
task_queue = f"tq-{uuid.uuid4()}"
50895096
handle1 = await client.start_workflow(
@@ -5964,9 +5971,9 @@ async def _do_first_completion_command_is_honored_test(
59645971
result = await handle.result()
59655972
except WorkflowFailureError as err:
59665973
if main_workflow_returns_before_signal_completions:
5967-
assert (
5968-
False
5969-
), "Expected no error due to main workflow coroutine returning first"
5974+
raise RuntimeError(
5975+
"Expected no error due to main workflow coroutine returning first"
5976+
)
59705977
else:
59715978
assert str(err.cause).startswith("Client should see this error")
59725979
else:

Diff for: tests/worker/workflow_sandbox/test_runner.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@
1212
from enum import IntEnum
1313
from typing import Callable, Dict, List, Optional, Sequence, Set, Type
1414

15-
import pytest
16-
1715
from temporalio import activity, workflow
1816
from temporalio.client import Client, WorkflowFailureError, WorkflowHandle
1917
from temporalio.exceptions import ApplicationError
@@ -28,6 +26,12 @@
2826
from tests.worker.workflow_sandbox.testmodules import stateful_module
2927
from tests.worker.workflow_sandbox.testmodules.proto import SomeMessage
3028

29+
# Passing through because Python 3.9 has an import bug at
30+
# https://github.com/python/cpython/issues/91351
31+
with workflow.unsafe.imports_passed_through():
32+
import pytest
33+
34+
3135
global_state = ["global orig"]
3236
# We just access os.name in here to show we _can_. It's access-restricted at
3337
# runtime only

0 commit comments

Comments
 (0)