Skip to content

test: cleanup obsolete and long-term skipped tests - #4

Merged
Million-mo merged 7 commits into
refactor/thin-wrapperfrom
feature/cleanup-obsolete-tests
Jul 3, 2026
Merged

test: cleanup obsolete and long-term skipped tests#4
Million-mo merged 7 commits into
refactor/thin-wrapperfrom
feature/cleanup-obsolete-tests

Conversation

@Million-mo

Copy link
Copy Markdown
Owner

Summary

This PR removes obsolete tests and long-term @pytest.mark.skip tests that are tied to architectures or APIs that no longer exist. It also fixes one test referencing a deleted file.

Changes

Removed obsolete test files (6 files)

  • tests/test_no_deprecation_warnings.py — TDD RED phase file; deprecation-warning coverage now lives in tests/compat/test_compat.py.
  • tests/messaging/test_runners.py — only contained a skipped test with pass; referenced removed pool.get_agent() API.
  • tests/phase8_merge_queue_removal_test.py — temporary regression test verifying a removed import is unimportable.
  • tests/phase8_shutdown_race_condition_test.py — temporary regression test using an undefined fixture.
  • tests/phase8_subagent_cascade_test.py — temporary regression test with no assertions.
  • tests/unit/test_open_code_config_cleanup.py — verified cleanup of fields already removed from OpenCodeConfig.

Removed long-term skipped tests (12 files modified)

Skipped tests removed because the underlying architecture has permanently changed:

  • run/turn separation refactor

    • tests/orchestrator/test_e2e.py::test_concurrent_sessions_turn_serialization_per_session
    • tests/orchestrator/test_run_handle.py::test_cancel_during_running_sets_cancelled
    • tests/orchestrator/test_session_controller.py::test_get_or_create_session_defaults_to_main_agent
    • tests/orchestrator/test_session_controller.py::test_get_or_create_session_agent_returns_shared_for_non_native
    • tests/orchestrator/test_session_controller.py::test_mcp_limit_falls_back_to_shared_agent
    • tests/orchestrator/test_close_session.py::test_flag_on_graceful_close
    • tests/orchestrator/test_close_session.py::test_flag_off_existing_behavior
    • tests/sessions/test_history_processors.py::test_compaction_and_processors_interaction
  • pool-less execution architecture

    • tests/toolsets/test_subagent_async.py::test_task_async_mode_writes_to_internal_fs
    • tests/toolsets/test_subagent_async.py::test_task_async_mode_with_nonexistent_agent_raises
    • tests/toolsets/test_input_provider_propagation.py::test_input_provider_propagated_when_session_bound_only
    • tests/verification/test_rfc0011_lineage.py::test_subagent_independent_session
  • other permanent architectural differences

    • tests/tools/test_workers.py::test_worker_team_emits_events
    • tests/tools/test_workers.py::test_delegation_depth_error_at_max_depth
    • tests/messaging/test_message_tracker.py::test_simple_sequential_chain
    • tests/messaging/test_message_tracker.py::test_parallel_to_sequential
    • tests/messaging/test_message_tracker.py::test_callback_chain
    • tests/servers/acp_server/test_acp_via_acp_snapshots.py::test_execute_command_simple

Fixed

  • tests/agents/test_import_corrections.py — removed reference to deleted tests/test_history.py.

Verification

  • uv run pytest --co now collects 4176/4256 tests (down from 4203/4283), reflecting removal of 27 obsolete/skipped tests.
  • Affected test directories were run: 1709 passed, 16 skipped, 3 failed.
  • The 3 failures (tests/tools/test_pick.py) are pre-existing and unrelated to this cleanup.

Follow-up work (out of scope)

Several @pytest.mark.xfail tests remain and should be addressed separately:

  • tests/tools/test_runcontext.py::test_capability_tools
  • tests/servers/opencode_server/test_input_provider.py (6 xfail tests)

Closes #N/A

Test added 7 commits July 3, 2026 10:25
… #93

- start_cleanup_task: start _start_cleanup_loop + strong task refs in _background_tasks set
- get_or_create_session_agent: validate session_id non-empty before proceeding
- create_team_from_config: use stateless cfg.get_agent() instead of session-bound agent (fixes MCP subprocess leak)
- _close_session_unlocked: wrap child session close in try-except (cascade resilience)
- close_session: same try-except for second child close loop
- event_bus _drain_dead_streams: catch all exceptions, not just anyio-specific ones
- event_bus close_session: same broad exception handling for send_stream aclose
- session_pool close_session: wrap in try-finally so EventBus + cache cleanup always runs

460 orchestrator tests pass, ruff + mypy clean.
Move heavy hooks (mypy full scan ~16s, pytest orchestrator suite ~30s)
from pre-commit to pre-push to keep commits fast (~2-5s). Pre-push runs
mypy + unit-marked tests as a safety net; full suite still runs in CI.
- Remove TDD RED phase file for deprecation warnings (covered by compat tests)
- Remove empty test_runners.py referencing removed pool.get_agent() API
- Remove phase8_* temporary regression tests (incomplete or testing removed imports)
- Remove OpenCodeConfig cleanup test verifying already-removed deprecated flags
Remove tests skipped due to permanent architectural shifts:
- run/turn separation refactor (orchestrator, sessions)
- pool-less execution architecture (subagent toolsets, verification)
- >> operator auto-forwarding deferred decision (message tracker)
- team worker event emission architectural difference (tools/workers)
- broken subprocess ACP bridge with equivalent snapshot coverage

Also fix test_import_corrections.py referencing deleted tests/test_history.py.
Remove 6 test functions permanently skipped due to architectural changes:
- test_run_stream_direct_gating: test_non_native_agent_executes_manual_loop
  (skip: run/turn separation refactor)
- test_break_behavior: test_interrupt_vs_break
  (skip: async generator cleanup deadlock — architecture issue)
- test_talks: test_group_stats_aggregation + orphaned nested test_team_connection
  (skip: flaky cross-test state pollution)
- test_message_timeout: test_sync_message_does_not_use_route_timeout (entire file)
  (skip: pre-SessionPool code path, no longer applicable)
- test_process_integration: test_process_output_limit
  (skip: output limit test needs refinement — never refined)
- test_cross_provider_session_lifecycle: test_subagent_child_session_parent_id_in_session_data
  (skip: Rich cell_len O(n) hang — instance divergence architecture issue)

Remove 3 debug/isolation test files (bugs fixed, tests served their purpose):
- test_thread_hypothesis.py: piping hang isolation test
- test_minimal_piping.py: duplicate piping hang isolation test
- test_debug_taskgroup.py: TaskGroup hang diagnostic test

Fix stale docstring in test_session_integration.py:
- Remove 'TDD RED phase' language (all 25 tests pass, RED phase long over)

Verification: 4161 tests collect (15 fewer), 60 affected tests pass
@Million-mo
Million-mo merged commit 3c711d9 into refactor/thin-wrapper Jul 3, 2026
Million-mo pushed a commit that referenced this pull request Jul 8, 2026
* spec: MCP session lifecycle fix — Phase 1

Add OpenSpec change for fixing stale MCP toolset cache and session-scoped
resource lifecycle bugs (#121). Includes:

- proposal.md: What & why (6 lifecycle fixes, no config changes)
- design.md: 8 design decisions (D1-D8) with Oracle + Momus review
- specs/mcp-session-lifecycle: 7 requirements, 14 scenarios
- specs/session-orchestration: Modified requirements for close path
- specs/unified-session-lifecycle: WebSocket disconnect hook
- tasks.md: 7 task groups, 46 tasks (P1a-P1f + E2E)
- tests/mcp_server/test_stale_mcp_connection.py: 5 reproduction tests

Reviewed by Momus (PASS) and Oracle (PASS) after 2 revision cycles.

Closes #121 (spec phase)

* spec: address Gemini Code Assist review comments

4 accepted fixes from dialectical analysis with Oracle:

1. Task 3.1/3.2/3.3: Change _session_connections to
   dict[str, set[tuple[str, int]]] — store (connection_id,
   session_key) pairs so AcpMcpConnectionManager.cleanup_session()
   can look up SessionStreamPair via session_key

2. Task 5.2 (D6): Two-layer cleanup on resume — call both
   SessionController.close_session() (RunHandle lifecycle) AND
   ACPSession.close() (ACP env/signals/prompts). Neither alone
   is sufficient.

3. Task 6.4 (D7): Same two-layer cleanup for WebSocket disconnect

4. Task 2.8: Use try/finally or fixture teardown for test cleanup

Rejected comments (2):
- hasattr(self.agent, 'mcp'): violates AGENTS.md, mcp always set
- hasattr(agent, 'mcp'): same, agent is not None check exists

Already addressed (2):
- Concurrency re-verify after lock: spec's lock-on-context design
  handles this implicitly
- await on_disconnect: type signature makes it obvious

* feat(mcp): add _SessionContext dataclass and session connection tracking

- Add _SessionContext dataclass to MCPManager with per-session state
  (connection_pool, toolset_cache, snapshot, acp_connection_ids, _cleanup_lock)
- Add _session_contexts dict to MCPManager.__init__
- Add _session_connections reverse index to AcpMcpConnectionManager
- Add register_session_connection() method for tracking session→connection mappings

Implements T1 and T6 of fix-mcp-session-lifecycle plan.

* feat(mcp): add session lifecycle methods and ACP cleanup

- get_or_create_session() and update_session_snapshot() on MCPManager (T2)
- add_acp_transport() on MCPManager for session-scoped ACP tracking (T3)
- register_session() returns tuple[SessionStreamPair, int] (T7, GAP-1)
- has_active_sessions() on AcpMcpConnection (T7)
- cleanup_session() with _cleanup_lock on AcpMcpConnectionManager (T7, GAP-12)
- Updated all callers of register_session() to unpack tuple return

* feat(mcp): cleanup_session on MCPManager and wire register_session_connection

- cleanup_session() with per-session _cleanup_lock on MCPManager (T4)
- _acp_mcp_manager field added for ACP cleanup delegation
- connect_acp_mcp_server() gains session_id parameter (T8, GAP-5)
- Returns tuple[str, int] (connection_id, session_key)
- Call site in session.py passes session_id and calls add_acp_transport
- All test callers updated for new signature

* test(mcp): add session lifecycle and ACP cleanup unit tests (T5+T9)

* refactor(mcp): change as_capability to session_id-based API (T10)

- Change as_capability(snapshot=, session_pool=) to as_capability(session_id=)
- Parameterize _make_capability with toolset_cache dict parameter (GAP-7)
- Split _process_snapshot into _process_global_configs and _process_session_configs
- GAP-11: KeyError fallback for concurrent cleanup_session race
- Backward compat: session_id=None processes self.servers with self._toolset_cache

* refactor(agent): update get_agentlet to use as_capability(session_id) (T12)

- Replace as_capability(snapshot=, session_pool=) with as_capability(session_id=)
- GAP-4: Use run_ctx.session_id from AgentRunContext instead of self._session_id
- Remove if/else branching on _mcp_snapshot — as_capability handles internally
- Keep _mcp_snapshot and _session_connection_pool field declarations for compat

* test(mcp): update caching+provider tests for session_id API (T13)

- Update 6 tests in test_mcpmanager_caching.py for new as_capability(session_id) API
- Update 15 failing tests in test_mcp_provider_lifecycle.py to use session context
- Fix static source assertion in test_no_dedup_hack_in_get_agentlet
- All 48 tests pass

* test(mcp): flip stale connection tests to verify fix (T14)

- Rename test_session_resume_returns_stale_toolset → _returns_fresh_toolset
- Rename test_multiple_acp_servers_all_go_stale → _get_fresh_toolsets
- Rename test_disconnect_all_clears_cache → test_cleanup_session_clears_per_session_cache
- All 5 tests now verify the fix instead of documenting the bug
- All tests pass with new session_id API

* feat(session): wire cleanup_session into ACPSession.close and SessionController (T15)

* feat(agent): wire get_or_create_session in SessionController agent creation (T16)

* test(mcp): integration tests for session close lifecycle (T17+T18+T19)

* fix(acp): resume_session close-then-recreate instead of early-return (T20)

* test(acp): resume_session lifecycle tests - close, reconnect, active run (T21+T22+T23)

* feat(acp): add on_disconnect callback to websocket handler (T24)

- Add on_disconnect: Callable[[AgentSideConnection], Awaitable[None]] | None parameter
- Generate UUID4 connection_id on AgentSideConnection at accept time (GAP-3)
- Call on_disconnect in ConnectionClosed handler before conn.close()
- Backward compatible: on_disconnect defaults to None

* feat(acp): implement close_all_sessions_for_connection (T25)

- Add _connection_sessions reverse index on ACPSessionManager
- Add connection_id parameter to create_session() and resume_session()
- Implement close_all_sessions_for_connection() for WebSocket disconnect cleanup
- Idempotent: pops connection_id, iterates sessions, closes via SessionController + ACPSession.close()

* feat(acp): wire on_disconnect to close_all_sessions_for_connection (T26)

- Add on_disconnect parameter to serve(), _serve_websocket(), _serve_streamable_http()
- Wire on_disconnect callback in ACPServer._start_async() closure
- Add session_manager field to AgentPoolACPAgent for shared session tracking
- Create shared ACPSessionManager in ACPServer for cross-connection session tracking
- Add disconnect detection in _serve_streamable_http via recv_task completion
- Fix test_resume_session_is_idempotent -> test_resume_session_closes_old_and_recreates
  (T20 changed resume_session from idempotent to close-then-recreate)

* test(acp): websocket disconnect closes sessions and preserves others (T27+T28)

- T27: test_websocket_disconnect_closes_all_sessions — 2 sessions same conn, disconnect, both closed
- T27: test_websocket_disconnect_preserves_other_connections — 2 conns, disconnect one, other survives
- T28: test_websocket_disconnect_during_run — active run cancelled with 2s timeout on disconnect

* fix(acp): resolve mypy union-attr errors with cast (T32) + add e2e session lifecycle test (T33)

- T32: Use cast() to type session_manager field as ACPSessionManager (not | None) for mypy
- T33: test_e2e_session_lifecycle — full lifecycle: connect→session→MCP→disconnect→reconnect→resume→verify fresh

* fix: resolve CI ruff format and lint errors

- ruff format: reformat 5 files (manager.py, session_controller.py, session.py, test_session_lifecycle.py, test_stale_mcp_connection.py)
- ruff check: shorten docstring in test_acp_session_resume.py (E501)

* fix(mcp): address review — _connection_sessions cleanup, get_or_create leaks

- Fix #1 (Critical): resume_session() now removes session_id from
  _connection_sessions before closing old session. Prevents stale
  connection disconnect from closing the newly resumed session.
- Fix #2 (High): as_capability() uses _session_contexts.get() instead of
  get_or_create_session(). Prevents memory leak when context was already
  cleaned up. Removes dead try/except KeyError code.
- Fix #3 (Medium): cleanup_session() uses _session_contexts.get() and
  returns early if None. Avoids creating throwaway SessionConnectionPool.
- TDD: 3 tests in test_review_fixes.py verify all fixes.

* fix(mcp): wire _acp_mcp_manager, add identity check, consolidate as_capability

Review round 2 fixes:

Fix #4 (Critical): Wire _acp_mcp_manager in ACPSession.__post_init__
- MCPManager._acp_mcp_manager was initialized to None and never set
- cleanup_session() could never delegate to AcpMcpConnectionManager
- Per-session ACP stream pairs and reverse-index entries leaked
- Fix: wire agent.mcp._acp_mcp_manager = acp_agent._mcp_manager in __post_init__

Fix #5 (Medium): Identity check after acquiring cleanup lock
- Concurrent cleanup_session() callers could do redundant work
- All ops were idempotent but wasteful (clearing empty dicts, etc.)
- Fix: check if self._session_contexts.get(session_id) is not ctx after lock

Fix #6 (Medium): Consolidate duplicated fallback in as_capability()
- Three identical 'for server in self.servers:' loops consolidated to one
- Pure readability refactor, zero behavior change

TDD: 3 new tests (2 RED before fix, 3 GREEN after)
- test_cleanup_session_delegates_to_acp_mcp_manager (unit)
- test_acp_session_wires_acp_mcp_manager (integration)
- test_cleanup_session_identity_check_prevents_redundant_work (unit)

213 tests pass, ruff clean.

* test(mcp): add 20 integration tests for session wiring lifecycle

Categories A-D from Oracle integration test plan:
- A (4): Cross-component wiring — cleanup delegation, __post_init__ wiring,
  full close chain, close_all_sessions_for_connection
- B (7): Lifecycle edge cases — full create/cleanup, close/recreate,
  shared connection isolation, WebSocket disconnect, resume, concurrent cleanup
- C (4): State consistency — registry consistency after cleanup/close/resume,
  stream pair unregistration
- D (5): Error paths — ACP manager raises, session close raises,
  MCP cleanup raises, resume old close raises, pool cleanup raises

These tests would have caught the _acp_mcp_manager wiring bug (round 2
review comment #1) that unit tests missed due to component isolation.

* fix(acp): wire connection_id through create_session/resume_session call sites

- Declare connection_id: str | None on AgentSideConnection (replaces monkey-patch)
- Remove # type: ignore[attr-defined] from transports.py connection_id assignments
- Add _get_connection_id() helper on AgentPoolACPAgent using isinstance check
- Wire connection_id= into all 5 create_session/resume_session call sites:
  new_session, load_session, fork_session, resume_session, handler.py
- Fix misleading GAP-11 comment: dict.get() returns None, never raises KeyError

Without this fix, _connection_sessions dict was never populated, making
close_all_sessions_for_connection() always return immediately — the entire
WebSocket disconnect cleanup feature was dead code.

* test(mcp): add 13 E2E integration tests for full MCP session lifecycle

Covers all 13 gap areas identified by Oracle analysis:
- G1: Full create_session → get_or_create_session_agent → MCPManager chain
- G2: as_capability with non-empty ACP snapshot → real MCPToolset
- G3: initialize_mcp_servers → connect_acp_mcp_server → AcpMcpTransport
- G4: Full tool execution through as_capability → MCPToolset → AcpMcpTransport
- G5: SessionController.close_session with real agent + real MCP resources
- G6: resume_session with real ACPSession (not patched)
- G7: Full on_disconnect → close_all_sessions_for_connection chain
- G8: connection_id propagation: create_session populates _connection_sessions
- G9: as_capability during concurrent cleanup (GAP-11 race)
- G10: ACP transport failure during tool execution + cleanup
- G11: Multiple sessions on same connection with real ACPSessions
- G12: Child session inherits parent's ACP transports
- G13: Pool shutdown cleans all session MCP resources

* fix: resolve CI mypy and unit test failures

- server.py: Remove unused type: ignore, use None guard for connection_id
- test_acp_session_resume.py: Add connection_id to expected resume_session call args

* chore(openspec): archive fix-mcp-session-lifecycle and sync specs

- Mark all 46 tasks as complete in tasks.md
- Sync 3 delta specs to main specs:
  - mcp-session-lifecycle (new)
  - session-orchestration (updated)
  - unified-session-lifecycle (updated)
- Archive to openspec/changes/archive/2026-07-07-fix-mcp-session-lifecycle/

* fix: parent session memory leak + on_disconnect in finally (review r3)

- session_controller.py: Replace get_or_create_session() with
  _session_contexts.get() when reading parent snapshot/pool. Prevents
  phantom _SessionContext creation when parent was already cleaned up.
- transports.py: Move on_disconnect callback from except ConnectionClosed
  to finally block. Ensures callback fires on any exception path.
- 3 TDD tests: leak detection, regression guard, disconnect coverage.

* fix(mcp): wire child session ACP manager, add transport callback, fix toolset __aexit__

Three fixes for child session ACP transport registration gaps:

1. Wire _acp_mcp_manager on child agent from parent (session_controller.py)
   - Child sessions created via get_or_create_session_agent() don't go
     through ACPSession.__post_init__, so _acp_mcp_manager stayed None.
     Now copied from parent after copy_pre_created_transports().

2. Add on_session_registered callback to AcpMcpTransport (acp_mcp_transport.py)
   - Optional callback invoked after register_session() with (connection_id,
     session_key). Enables callers to register ACP connections for cleanup
     tracking via register_session_connection().

3. Fix toolset_cache.clear() to call __aexit__ first (manager.py)
   - cleanup_session() called .clear() without closing MCPToolset instances,
     leaking stream pairs and forwarder tasks. Now mirrors disconnect_all()
     pattern: iterate values, call __aexit__(None, None, None) with
     contextlib.suppress(ValueError), then clear.

TDD: 3 tests in test_child_session_acp_fix.py (all GREEN).
252 MCP+ACP tests pass, 0 regressions, ruff clean.
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.

1 participant