Skip to content

feat(test): activity test environment - #151

Merged
shijiesheng merged 2 commits into
cadence-workflow:mainfrom
shijiesheng:test-activity
Aug 5, 2026
Merged

feat(test): activity test environment#151
shijiesheng merged 2 commits into
cadence-workflow:mainfrom
shijiesheng:test-activity

Conversation

@shijiesheng

Copy link
Copy Markdown
Member

What changed?

Why?

How did you test it?

Potential risks

Release notes

Documentation Changes

Comment on lines +175 to +177
self._thread_pool = ThreadPoolExecutor(
max_workers=1, thread_name_prefix="cadence-test-activity"
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Edge Case: Timeout on non-cooperative sync activity leaks the worker thread

The thread pool is created with max_workers=1, and the set_test_timeout path cancels the asyncio task wrapping context.execute. For a sync activity, execution runs via loop.run_in_executor on that single thread; cancelling the awaiting coroutine does not stop the underlying blocking thread. After a timeout on a sync activity, the thread stays occupied and close() uses shutdown(wait=False), so the thread leaks and any subsequent execute_activity on the same env blocks forever waiting for a free worker. Only async timeouts are covered by tests. Consider documenting this limitation, or noting in set_test_timeout that sync activities that ignore is_cancelled() cannot be interrupted.

Was this helpful? React with 👍 / 👎

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will address in the new PR

Comment thread cadence/testing/_activity_environment.py
@codecov

codecov Bot commented Jul 13, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.68293% with 9 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
cadence/testing/_activity_environment.py 92.62% 7 Missing and 2 partials ⚠️
Files with missing lines Coverage Δ
cadence/testing/__init__.py 100.00% <100.00%> (ø)
cadence/testing/_activity_environment.py 92.62% <92.62%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

_TASK_TOKEN = b"test-task-token"


class _FakeWorkerStub:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: instead of fakeworkerstub, SimulatedWorkerStub might be a better name here since we are simulating a worker grpc stub.

@timl3136 timl3136 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Signed-off-by: Shijie Sheng <liouvetren@gmail.com>
Signed-off-by: Shijie Sheng <liouvetren@gmail.com>
@shijiesheng
shijiesheng enabled auto-merge (squash) August 5, 2026 17:57
@gitar-bot

gitar-bot Bot commented Aug 5, 2026

Copy link
Copy Markdown
Code Review 👍 Approved with suggestions 1 resolved / 2 findings

Adds a new TestActivityEnvironment utility to enable standalone unit testing of sync and async activities. Consider addressing the thread leak in non-cooperative sync activity timeouts.

💡 Edge Case: Timeout on non-cooperative sync activity leaks the worker thread

📄 cadence/testing/_activity_environment.py:175-177 📄 cadence/testing/_activity_environment.py:288-302

The thread pool is created with max_workers=1, and the set_test_timeout path cancels the asyncio task wrapping context.execute. For a sync activity, execution runs via loop.run_in_executor on that single thread; cancelling the awaiting coroutine does not stop the underlying blocking thread. After a timeout on a sync activity, the thread stays occupied and close() uses shutdown(wait=False), so the thread leaks and any subsequent execute_activity on the same env blocks forever waiting for a free worker. Only async timeouts are covered by tests. Consider documenting this limitation, or noting in set_test_timeout that sync activities that ignore is_cancelled() cannot be interrupted.

✅ 1 resolved
Quality: Confusingly similar set_heartbeat_details vs get_heartbeat_details

📄 cadence/testing/_activity_environment.py:200-206 📄 cadence/testing/_activity_environment.py:232-245
set_heartbeat_details seeds the values that the activity reads back via activity.heartbeat_details() (simulated prior-attempt input), while get_heartbeat_details returns the details the activity emitted via activity.heartbeat() during this run (output). The near-identical names obscure that they operate on opposite data flows. Consider renaming get_heartbeat_details to something like get_last_heartbeat_details / get_recorded_heartbeat_details, or clarifying the distinction more prominently in the docstrings.

🤖 Prompt for agents
Code Review: Adds a new TestActivityEnvironment utility to enable standalone unit testing of sync and async activities. Consider addressing the thread leak in non-cooperative sync activity timeouts.

1. 💡 Edge Case: Timeout on non-cooperative sync activity leaks the worker thread
   Files: cadence/testing/_activity_environment.py:175-177, cadence/testing/_activity_environment.py:288-302

   The thread pool is created with max_workers=1, and the set_test_timeout path cancels the asyncio task wrapping context.execute. For a sync activity, execution runs via loop.run_in_executor on that single thread; cancelling the awaiting coroutine does not stop the underlying blocking thread. After a timeout on a sync activity, the thread stays occupied and close() uses shutdown(wait=False), so the thread leaks and any subsequent execute_activity on the same env blocks forever waiting for a free worker. Only async timeouts are covered by tests. Consider documenting this limitation, or noting in set_test_timeout that sync activities that ignore is_cancelled() cannot be interrupted.

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Showing less information.

Comment with these commands to change the behavior for this request:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

@shijiesheng
shijiesheng merged commit 70cd17a into cadence-workflow:main Aug 5, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants