-
Notifications
You must be signed in to change notification settings - Fork 1.1k
feat: add a python system package pytest_ten supporting AAA-style tests
#1838
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
pytest_ten supporting AAA-style tests pytest_ten supporting AAA-style tests
Pull Request ReviewThis PR adds a new Python system package ✅ StrengthsCode Quality
Testing
|
| Category | Rating | Notes |
|---|---|---|
| Code Quality | ⭐⭐⭐⭐ | Well-structured, clean design |
| Documentation | ⭐⭐ | Good inline docs, missing README |
| Testing | ⭐⭐⭐ | Good examples, missing edge cases |
| Security | ⭐⭐⭐⭐⭐ | No concerns |
| Performance | ⭐⭐⭐ | Adequate, some optimization opportunities |
| Overall | ⭐⭐⭐⭐ | Recommended with minor revisions |
🎯 Action Items
Before Merge:
- ❗ Fix the README files with actual content (high priority)
- ❗ Document the race condition in put_back parameter or remove it
- ❗ Add resource cleanup in on_deinit
Future Enhancements:
- Add comprehensive test coverage for all code paths
- Consider performance optimizations for high-throughput scenarios
- Add migration guide from old test patterns
- Update to modern asyncio APIs
Great work on this feature! The core implementation is solid and provides valuable testing capabilities. The main concerns are around documentation completeness and a few edge cases in the filtering logic. Once the README is updated and cleanup is added, this will be ready to merge.
Code Review: pytest_ten System PackageThank you for this comprehensive addition of pytest testing infrastructure! This is a valuable enhancement that provides AAA-style testing for TEN extensions. Here's my detailed review: ✅ Strengths
🐛 Potential Issues1. asyncio.get_event_loop() Deprecation (Medium Priority)Location: # Current code (deprecated in Python 3.10+)
end_time = asyncio.get_event_loop().time() + timeoutIssue: Recommendation: Use end_time = asyncio.get_running_loop().time() + timeoutThis pattern appears in:
2. Resource Cleanup in _TenTestRunner.on_deinit() (Low Priority)Location: async def on_deinit(self, ten_env: AsyncTenEnvTester) -> None:
if self._test_task:
self._test_task.cancel()
try:
await self._test_task
except asyncio.CancelledError:
passIssue: Queues in Recommendation: Consider adding cleanup: async def on_deinit(self, ten_env: AsyncTenEnvTester) -> None:
if self._test_task:
self._test_task.cancel()
try:
await self._test_task
except asyncio.CancelledError:
pass
# Clear queues to prevent memory leaks
if self._ctx:
while not self._ctx.received_cmds.empty():
self._ctx.received_cmds.get_nowait()
while not self._ctx.received_data.empty():
self._ctx.received_data.get_nowait()
# ... clear other queues3. Potential Race Condition in put_back Logic (Low Priority)Location: if put_back:
await self.received_data.put(data)
await asyncio.sleep(0.05) # Small delay to avoid busy loopIssue: The Note: This is likely acceptable for testing scenarios, but worth documenting the limitation. 🔒 Security Considerations✅ No security issues identified. The code operates in a test context and doesn't handle user input or network data directly. ⚡ Performance Considerations1. Timeout Polling OverheadThe attempt_timeout = min(remaining, 0.1)Assessment: This is reasonable for tests, but adds 100ms latency in the worst case. For high-frequency testing, this could add up. Recommendation: Consider making the poll interval configurable, or use an event-based approach with 2. Message Cloningawait self._ctx.received_cmds.put(cmd.clone())
await self._ctx.received_data.put(data.clone())Assessment: Good defensive programming to prevent mutation issues. The performance cost is acceptable for testing. 📝 Code Quality1. Inconsistent README PlaceholdersLocation: The README files contain placeholder content: # Default Extension Python Extension
## Features
- xxx featuresRecommendation: Replace with actual # pytest_ten - TEN Framework Pytest Integration
`pytest_ten` provides AAA (Arrange-Act-Assert) style testing helpers for TEN Framework extensions.
## Features
- Clean `@ten_test` decorator for pytest integration
- Context-based API for sending/receiving messages
- Built-in timeout and assertion helpers
- Support for pytest fixtures
- Mock command and data responses2. Type Hints ConsistencyThe code uses modern Python 3.10+ type hints ( 🧪 Test CoverageExample Tests Look GoodThe integration tests demonstrate proper usage:
Suggestion: Consider adding a test for the 📦 Build ConfigurationBUILD.gn Issues✅ Properly configured - The package correctly includes all necessary files and sets up dependencies. Minor Note: The 🎯 Recommendations SummaryHigh Priority
Medium Priority
Low Priority
✨ Overall AssessmentThis is a well-designed and valuable addition to the TEN Framework! The API is intuitive, the documentation is thorough, and the integration with pytest is seamless. The main issue is the Recommendation: Approve with minor changes (fix the event loop deprecation) Great work! 🎉 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR is being reviewed by Cursor Bugbot
Details
Your team is on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle for each member of your team.
To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.
| ) -> None: | ||
| assert self._ctx is not None | ||
|
|
||
| await self._ctx.received_video.put(video_frame) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Audio and video frames not cloned before queueing
In on_audio_frame and on_video_frame, the frames are put directly into the queues without calling .clone(), while on_cmd and on_data correctly clone their messages before queueing. This inconsistency could cause issues if the runtime modifies or deallocates the original frame objects after the callback returns, leading to accessing invalid or corrupted data when the test consumes from the queue.
PR Review: pytest_ten System PackageOverall AssessmentThis is a well-structured and valuable addition to the TEN Framework. The AAA-style testing utilities significantly improve the developer experience for writing Python extension tests. The implementation demonstrates good software engineering practices with comprehensive error handling, clear documentation, and practical examples. ✅ Strengths1. Code Quality & Architecture
2. Testing Features
3. Error Handling
|
Pull Request Review: Add pytest_ten System PackageOverviewThis PR introduces ✅ Strengths1. Clean Architecture
2. Comprehensive API
3. Good Error Handling
4. Integration & CI
🐛 Potential Issues & ImprovementsCritical Issues1. Race Condition in Message Filtering (ten_test.py:88-94, 136-142) The if name and data.get_name() != name:
if put_back:
await self.received_data.put(data)
await asyncio.sleep(0.05) # Small delay to avoid busy loop
continueIssue: When multiple tasks are consuming from the same queue, a message put back might be consumed by a different waiter before the original waiter retries. Recommendation: Consider using a more robust pattern:
2. Event Loop Access Pattern (ten_test.py:74, 122, etc.) Using end_time = asyncio.get_event_loop().time() + timeout
remaining = end_time - asyncio.get_event_loop().time()Recommendation: Use loop = asyncio.get_running_loop()
end_time = loop.time() + timeout
remaining = end_time - loop.time()This is more explicit and avoids deprecated API usage. Design Concerns3. Message Cloning Strategy Messages are cloned before queuing: await self._ctx.received_cmds.put(cmd.clone()) # Line 449
await self._ctx.received_data.put(data.clone()) # Line 471But audio/video frames are not: await self._ctx.received_audio.put(audio_frame) # Line 484
await self._ctx.received_video.put(video_frame) # Line 491Question: Is this intentional? If frames are mutable, this could lead to issues. Consider documenting why frames aren't cloned or clone them for consistency. 4. Unbounded Queue Growth All message queues are unbounded: self.received_cmds: asyncio.Queue[Cmd] = asyncio.Queue()Risk: If an extension sends many messages that aren't consumed, memory could grow unbounded. Recommendation: Consider either:
🔍 Code QualityGood Practices ✅
Minor Issues5. Unused Import (ten_test.py:3) import inspect # Only used in decorator, could be moved to function scope if desiredMinor: Not a real issue, but 6. Magic Numbers attempt_timeout = min(remaining, 0.1) # Line 84, 132
await asyncio.sleep(0.05) # Line 92, 140Recommendation: Extract as named constants: _POLL_INTERVAL = 0.1
_PUT_BACK_DELAY = 0.057. Documentation Gaps The README files (packages/core_system/pytest_ten/docs/README.*.md) are placeholder templates and don't document the actual package. This should be updated before release. 🔒 SecurityNo security concerns identified.
⚡ PerformanceConcerns8. Busy-Wait Pattern in expect_ Methods* The implementation polls every 0.1 seconds: while True:
remaining = end_time - asyncio.get_event_loop().time()
if remaining <= 0:
raise TimeoutError(...)
try:
attempt_timeout = min(remaining, 0.1)
data = await asyncio.wait_for(self.received_data.get(), timeout=attempt_timeout)Observation: This creates unnecessary wake-ups every 100ms. While not critical for tests, it's not ideal. Alternative: Could use a single try:
data = await asyncio.wait_for(self.received_data.get(), timeout=timeout)
if name and data.get_name() != name:
# handle mismatch
except asyncio.TimeoutError:
raise TimeoutError(...)But current approach allows for name filtering, so trade-off may be acceptable for tests. 🧪 Test CoverageCoverage is good:
Suggestion: Consider adding tests for:
📋 Build System & CIWell integrated:
One observation: 📝 Recommendations SummaryMust Fix Before Merge
Should Consider
Nice to Have
🎯 Overall AssessmentThis is a high-quality PR that adds valuable testing infrastructure to the TEN Framework. The implementation is clean, well-documented, and provides an excellent developer experience. The few issues identified are minor and don't block the core functionality. Recommendation: Approve with minor changes (address the deprecated API usage and documentation at minimum) Great work! 🚀 |
Code Review: pytest_ten System PackageSummaryThis PR introduces a well-designed pytest integration package ( ✅ Strengths1. Excellent API Design
2. Strong Documentation
3. Robust Error Handling
4. Complete Integration
5. Good Testing Patterns
🔍 Issues FoundCritical Issues1. Race Condition in Message Filtering (packages/core_system/pytest_ten/pytest_ten/ten_test.py:89-92, 137-140)The if put_back:
# Put back and wait before retrying
await self.received_data.put(data)
await asyncio.sleep(0.05) # Small delay to avoid busy loopProblem: If messages arrive while waiting, they could be reordered. The queue doesn't preserve order when putting items back. Impact: Tests using Recommendation:
2. Deprecated API Usage (packages/core_system/pytest_ten/pytest_ten/ten_test.py:74, 122, 200, etc.)Multiple uses of end_time = asyncio.get_event_loop().time() + timeoutProblem: Impact: Could cause warnings or failures in future Python versions. Recommendation: Replace with end_time = asyncio.get_running_loop().time() + timeoutHigh Priority Issues3. Missing Clone on Audio/Video Frames (packages/core_system/pytest_ten/pytest_ten/ten_test.py:484, 491)await self._ctx.received_audio.put(audio_frame) # Not cloned\!
await self._ctx.received_video.put(video_frame) # Not cloned\!Problem: Commands and data are cloned (line 449, 471), but audio/video frames are not. This could cause memory issues if frames are mutated. Recommendation: Either clone frames or document why they shouldn't be cloned: await self._ctx.received_audio.put(audio_frame.clone()) # If clone() exists4. Unused Import (packages/core_system/pytest_ten/pytest_ten/ten_test.py:3)import inspect
import tracebackProblem: Recommendation: Verify both are needed, remove if not. Medium Priority Issues5. Task Cancellation Without Cleanup (packages/core_system/pytest_ten/pytest_ten/ten_test.py:414-420)async def on_deinit(self, ten_env: AsyncTenEnvTester) -> None:
if self._test_task:
self._test_task.cancel()
try:
await self._test_task
except asyncio.CancelledError:
passProblem: If the test is cancelled mid-operation (e.g., during Recommendation: Consider adding cleanup logic or documenting expected behavior on cancellation. 6. Hardcoded Timeout Values (packages/core_system/pytest_ten/pytest_ten/ten_test.py:84)attempt_timeout = min(remaining, 0.1)
await asyncio.sleep(0.05)Problem: Magic numbers make the code harder to tune for different environments. Recommendation: Extract as class constants: _QUEUE_POLL_INTERVAL = 0.1 # seconds
_PUT_BACK_DELAY = 0.05 # seconds7. Version Mismatch Risk (packages/core_system/pytest_ten/pyproject.toml:8 vs manifest.json:4)
Problem: These versions don't match, which could cause confusion about the package version. Recommendation: Align versions or document why they differ. Typically, manifest.json should be the source of truth for TEN packages. 8. Missing Type Hints for Queues (packages/core_system/pytest_ten/pytest_ten/ten_test.py:31-34)The generic types on Queue declarations are good, but Python 3.10+ should use Current: self.received_cmds: asyncio.Queue[Cmd] = asyncio.Queue()Recommendation: This is actually correct for asyncio.Queue. No change needed, but ensure type checking passes. Low Priority / Nitpicks9. Inconsistent Assertion Messages (packages/core_system/pytest_ten/pytest_ten/ten_test.py:606)assert err is None, f"Test failed: {err.error_message()}"Problem: This could raise Recommendation: Use defensive access: assert err is None, f"Test failed: {err.error_message() if err else 'unknown'}"10. README Templates Not Updated (packages/core_system/pytest_ten/docs/README.*.md)The README files contain placeholder text like "Default Extension Python Extension" and "xxx features". Recommendation: Update with actual pytest_ten documentation before merging. 11. Missing uv.lock in .gitignore? (packages/core_system/pytest_ten/uv.lock)A 147-line Recommendation: Verify if this should be in version control or .gitignore'd. 🎯 Best Practices & QualityGood Practices Observed:
Minor Suggestions:
🔒 SecurityNo security concerns identified. The package:
⚡ PerformancePerformance considerations:
Suggestion: For high-throughput tests, consider making the polling interval configurable. 🧪 Test CoverageExcellent test coverage:
Minor gap: No explicit tests for 📋 Summary
🚀 Recommendations for MergeBefore merging:
After these fixes, this PR is ready to merge. The new pytest_ten package is a valuable addition that will significantly improve the testing experience for TEN extensions. Great work! This is a well-architected addition to the framework. 🎉 |
Pull Request Review: pytest_ten System PackageSummaryThis PR introduces a new Python system package pytest_ten that provides AAA-style testing utilities for TEN extensions. The implementation is well-structured and adds significant value to the testing infrastructure. Critical Issues Found1. Missing clone() for AudioFrame/VideoFrame (ten_test.py:502, 509) Unlike on_cmd and on_data which clone the messages, audio/video frames are not cloned before being put in the queue. This could lead to data corruption if the frame is modified elsewhere. 2. README Documentation is Placeholder The docs/README.en-US.md contains only placeholder text copied from a template and should be updated with actual pytest_ten documentation. Detailed ReviewSee full review in next comment... |
StrengthsCode Quality
Design Patterns
Integration
|
All Issues FoundCritical Issues1. Missing clone() for AudioFrame/VideoFrame
Medium Priority2. Type Annotation Inconsistency
3. README is Placeholder
Low Priority4. Busy-Wait Pattern
5. Missing Type Hints
|
Test Coverage AnalysisGood
Missing
Recommendation: Add a test suite under packages/core_system/pytest_ten/tests/ to test the testing framework itself. Security & PerformanceSecurity
PerformancePositive:
Concerns:
|
RecommendationsMust Fix Before Merge
Should Fix Soon After Merge
Nice to Have
Overall AssessmentThis is a well-designed and valuable addition to the TEN Framework testing infrastructure. The AAA-style approach with TenTestContext is much more intuitive than the callback-based approach. The implementation is solid with only a few critical issues that need addressing. Recommendation: Approve with minor changes required (fix the cloning issue and documentation). Score: 8.5/10 The main detractors are:
Once these issues are addressed, this will be an excellent addition to the codebase. The refactoring to named callbacks in async_test.py is a nice improvement for debuggability. |
|
|
||
| async def send_video_frame(self, frame: VideoFrame) -> None: | ||
| """Send video frame to extension""" | ||
| await self.ten_env.send_video_frame(frame) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Send methods silently discard error return values
The send_data, send_audio_frame, and send_video_frame methods in TenTestContext declare a return type of None but the underlying AsyncTenEnvTester methods return TenError | None. The returned error values are being silently discarded, which could cause tests to appear to pass when send operations actually fail. These methods need to propagate the error return value to callers.
Pull Request Review: pytest_ten System PackageI've completed a comprehensive review of this PR. Overall, this is a well-structured addition that introduces AAA-style testing capabilities to the TEN Framework. Here's my detailed feedback: ✅ Strengths1. Excellent Code Quality
2. Comprehensive API Design
3. Robust Error Handling
4. Good Refactoring in async_test.py
|
Pull Request Review: pytest_ten System PackageOverviewThis PR introduces a new Python system package ✅ Strengths1. Architecture & Design
2. Code Quality
3. Testing Infrastructure
|
Pull Request Review: pytest_ten System PackageThis PR introduces a well-designed pytest integration system for TEN Framework that enables AAA (Arrange-Act-Assert) style testing. The implementation is solid overall with comprehensive features and good integration with the existing codebase. StrengthsArchitecture and Design
Code Quality
Integration
Issues and Suggestions1. Potential Race Condition in put_back LogicLocation: packages/core_systems/pytest_ten/pytest_ten/ten_test.py:91-96 The put_back feature has a subtle race condition. If multiple messages arrive rapidly, the queue ordering may be disrupted when putting messages back. Recommendation: Add a warning in documentation about put_back=True limitations with high-frequency message streams. 2. Missing Return Type HandlingLocation: packages/core_systems/pytest_ten/pytest_ten/ten_test.py:42-43 The send_data and similar methods return None but underlying ten_env.send_data() might return TenError. Consider checking return value and raising exception on error, or changing return type to TenError | None for consistency with send_cmd(). 3. Inconsistent Timeout BehaviorThe expect methods use polling with 0.1s attempts, while expect_audio_frame/video_frame use direct waits. Recommend standardizing timeout behavior across all expect methods for consistency. 4. Event Loop DeprecationMultiple places use asyncio.get_event_loop() which is soft-deprecated in Python 3.10+. Recommend using asyncio.get_running_loop() instead. 5. Pytest Fixture Support - Incomplete ImplementationLocation: packages/core_systems/pytest_ten/pytest_ten/ten_test.py:418-421 The fixture storage (self._pytest_fixtures) exists but is never populated! The decorator does not extract pytest fixtures. Either implement fixture extraction or remove the incomplete code to avoid confusion. 6. Documentation: Missing Dropped Messages WarningThe put_back=False default silently drops unmatched messages, which could lead to confusing test failures. Add prominent warning in docstrings about this behavior. 7. Directory Name InconsistencyThe package is in packages/core_systems/ but BUILD.gn references core_system (singular). Check if this is intentional. Security ConsiderationsNo security issues identified. Test-only code with appropriate isolation. Test CoverageGood: New test file test_mock.py demonstrates both old and new testing styles. Suggestions: Add tests for edge cases (timeout scenarios, put_back=True with multiple messages, collect_all with empty queues, assert_no methods, streaming mock responses). Performance Considerations
SummaryOverall Assessment: Approve with minor fixes recommended This is a well-executed feature that significantly improves testing ergonomics for TEN Framework. The core implementation is solid with good design patterns. Priority Fixes:
Nice-to-Have:
The PR is ready to merge after addressing the pytest fixture issue - it is currently non-functional code that could confuse users. Great work on this feature! |
* fix: remove the version lock on ten_ai_base (#1818) * fix: remove the version lock on ten_ai_base * fix: revert --------- Co-authored-by: Ethan Zhang <[email protected]> * feat: add a python system package `pytest_ten` supporting AAA-style tests (#1838) * feat: add a python test wrapper supporting AAA-style tests * fix: use relative import * feat: move test_wrapper from ten_runtime into core_system package * test: add example tests using pytest_ten * chore: refine code * feat: update workflow to upload pytest_ten system package * fix: refine code * fix: test case on windows --------- Co-authored-by: xxxxl_sun <[email protected]> Co-authored-by: sunxilin <[email protected]> * fix: elevenlabs asr language (#1842) Co-authored-by: liaochenliang <[email protected]> * feat: support tman install app (#1845) Co-authored-by: Hu Yueh-Wei <[email protected]> * refactor(property): rename max_tokens to max_completion_tokens for clarity (#1848) Update property.json files to use more descriptive parameter name max_completion_tokens instead of max_tokens. Also includes minor text and voice setting adjustments. * feat: add gradium tts (#1843) * feat: add gradium tts * style(gradium_tts_python): improve code formatting and line wrapping * refactor: simplify error logging and config handling * fix: update licence when uploading to ppa (#1851) * feat: winget (#1844) * feat: winget (dry run when push) * fix: remove potential code injection * fix: variable format * fix: build command args * chore: test production run, trigger PR to winget-pkgs * fix: higher rate limit * Revert "chore: test production run, trigger PR to winget-pkgs" This reverts commit 4d5d6e0. * chore: modify PackageIdentifier * chore: refine codes * fix: trigger * chore: refine codes * chore: refine codes * chore: refine template * fix: license type * fix: refine codes --------- Co-authored-by: Nie Zhihe <[email protected]> Co-authored-by: Hu Yueh-Wei <[email protected]> * fix: update minimax api endpoint from .com to .io (#1852) * refactor: simplify build command by removing redundant clean task (#1849) Co-authored-by: Ethan Zhang <[email protected]> * fix(voice-assistant-live2d): update voice settings and api endpoint * fix: update minimax websocket url from minimaxi.io to minimax.io (#1854) --------- Co-authored-by: xxxxl_sun <[email protected]> Co-authored-by: Ethan Zhang <[email protected]> Co-authored-by: Jun <[email protected]> Co-authored-by: sunxilin <[email protected]> Co-authored-by: liaochenliang <[email protected]> Co-authored-by: liaochenliang <[email protected]> Co-authored-by: Hu Yueh-Wei <[email protected]> Co-authored-by: Nie Zhihe <[email protected]> Co-authored-by: Nie Zhihe <[email protected]>
Note
Introduces the
pytest_tensystem package for pytest-based AAA-style testing and wires it into build, packaging/publishing, CI, versioning scripts, and Python integration tests.packages/core_systems/pytest_tenTenTestContext,ten_testdecorator.BUILD.gn), manifest, docs,pyproject.toml,uv.lock, and publish target.//packages/core_systemsinten_framework_all.pytest_tento editor/type-checker paths (.vscode/settings.json,pyrightconfig.json).ten_packages/system/pytest_tenalongside other system packages.pytest_ten.dev_dependenciesin manifests.pytest_tento version update pipeline.AsyncTenEnvTesterto named functions for queue handling.pytest_ten; adddev_dependenciesonpytest_tenand adjust start scripts to include it.Written by Cursor Bugbot for commit 9884229. This will update automatically on new commits. Configure here.