Skip to content

test: move TcpProxy to tests/tcp_proxy.py to fix collection - #966

Merged
Lorak-mmk merged 1 commit into
scylladb:masterfrom
dawmd:i965
Aug 4, 2026
Merged

test: move TcpProxy to tests/tcp_proxy.py to fix collection#966
Lorak-mmk merged 1 commit into
scylladb:masterfrom
dawmd:i965

Conversation

@dawmd

@dawmd dawmd commented Aug 4, 2026

Copy link
Copy Markdown

tests/unit/test_tcp_proxy.py, added in d99dc46, imported its subject (TcpProxy) from tests/integration/standard/test_client_routes.py, which transitively imports tests/integration/init.py. That module guards its ccmlib imports with try/except ImportError, but then unconditionally declares class Cassandra41CCMCluster(CCMCluster) at module level, so on any environment without ccmlib installed the import fails with:

NameError: name 'CCMCluster' is not defined

This broke test collection consistently on the windows-2022 job, where ccmlib is absent. The latent defect in tests/integration/init.py predates d99dc46; that commit merely became the first unit test to import tests.integration and thus the first to expose it.

TcpProxy is a plain socket-based helper -- it depends only on socket, select and threading, and needs neither CCM nor a running Cassandra/Scylla cluster -- so it does not belong behind that import. Move it verbatim into a new tests/tcp_proxy.py and import it from both call sites:

  • tests/integration/standard/test_client_routes.py now imports TcpProxy from tests.tcp_proxy; its select and socket imports, used only by the moved class, are dropped.
  • tests/unit/test_tcp_proxy.py imports from tests.tcp_proxy and no longer needs its os.environ.setdefault("CASSANDRA_VERSION", ...) shim, which existed solely to get tests.integration's module-level version parsing to succeed. The shim and the docstring paragraph explaining it are removed.

The class body is byte-identical to the original; only the new module's license header, docstring and imports are new. No driver code is touched and no test behavior changes.

Validation:

  • pytest tests/unit/test_tcp_proxy.py: 2 passed with neither CASSANDRA_VERSION nor SCYLLA_VERSION set, i.e. the unit test no longer imports tests.integration at all.
  • tests/integration/standard/test_client_routes.py compiles clean with no imports left unused.

Fixes: #965

Pre-review checklist

  • I have split my patch into logically separate commits.
  • All commit messages clearly explain what they change and why.
  • (N/A) I added relevant tests for new features and bug fixes.
  • All commits compile, pass static checks and pass test.
  • PR description sums up the changes and reasons why they should be introduced.
  • (N/A) I have provided docstrings for the public items that I want to introduce.
  • (N/A) I have adjusted the documentation in ./docs/source/.
  • I added appropriate Fixes: annotations to PR description.

Copilot AI balanced review requested due to automatic review settings August 4, 2026 09:42
@dawmd dawmd self-assigned this Aug 4, 2026
@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: QUIET

Plan: Pro Plus

Run ID: 8b27170d-5872-4c07-8c9e-98dbfdd8d1f0

📥 Commits

Reviewing files that changed from the base of the PR and between f634104 and f293f5a.

📒 Files selected for processing (3)
  • tests/integration/standard/test_client_routes.py
  • tests/tcp_proxy.py
  • tests/unit/test_tcp_proxy.py

📝 Walkthrough

Walkthrough

The TCP proxy moved to tests.tcp_proxy. The helper provides lifecycle control, backend retargeting, connection tracking, forced drops, bidirectional forwarding, and cleanup. Integration and unit tests now use the shared helper. The unit test no longer imports the integration module or sets CASSANDRA_VERSION.

Possibly related PRs

Suggested reviewers: mykaul

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main change: moving TcpProxy to tests/tcp_proxy.py to fix test collection.
Description check ✅ Passed The description explains the cause, implementation, validation, scope, linked issue, and completed checklist items.
Linked Issues check ✅ Passed The changes satisfy issue #965 by preventing unit tests from importing integration infrastructure without ccmlib.
Out of Scope Changes check ✅ Passed The changes are limited to relocating the test helper, updating imports, and removing the obsolete environment workaround.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

Comment @coderabbitai help to get the list of available commands.

@dawmd dawmd mentioned this pull request Aug 4, 2026
8 tasks

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Moves TcpProxy into a dependency-free test helper module, preventing unit-test collection from importing CCM-dependent integration code and resolving issue #965.

Changes:

  • Extracts TcpProxy into tests/tcp_proxy.py.
  • Updates unit and integration tests to import the shared helper.
  • Removes obsolete environment setup and unused imports.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
tests/tcp_proxy.py Adds the standalone TCP proxy helper.
tests/unit/test_tcp_proxy.py Imports the helper without integration dependencies.
tests/integration/standard/test_client_routes.py Uses the extracted helper and removes its former implementation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@dawmd dawmd mentioned this pull request Aug 4, 2026
8 tasks

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/tcp_proxy.py`:
- Around line 88-91: Make retarget() update target_host and target_port while
holding _lock, and update _handle_new_connection() to capture both values under
the same lock before calling connect(). Release the lock before any connection
attempt so the snapshot is consistent without blocking connection establishment.
- Around line 72-80: Update _handle_new_connection so the backend
target_sock.connect attempt is bounded and observes shutdown state, rather than
blocking indefinitely on the listener thread. Ensure a shutdown can interrupt or
terminate the pending connection and that the socket is tracked or closed
consistently before stop() joins the listener and client connections. Apply the
same behavior to the corresponding connection path around the second referenced
location.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: QUIET

Plan: Pro Plus

Run ID: 06d1f484-c8e7-4f61-8746-91297e1874c4

📥 Commits

Reviewing files that changed from the base of the PR and between bbd4f05 and f634104.

📒 Files selected for processing (3)
  • tests/integration/standard/test_client_routes.py
  • tests/tcp_proxy.py
  • tests/unit/test_tcp_proxy.py

Comment thread tests/tcp_proxy.py
Comment thread tests/tcp_proxy.py
@dawmd

dawmd commented Aug 4, 2026

Copy link
Copy Markdown
Author

The failure looks like #580:

Failure
  =================================== FAILURES ===================================
  ___________ HostConnectionTests.test_successful_wait_for_connection ____________
  
  self = <tests.unit.test_host_connection_pool.HostConnectionTests testMethod=test_successful_wait_for_connection>
  
      def test_successful_wait_for_connection(self):
          host = Mock(spec=Host, address='ip1')
          session = self.make_session()
          conn = HashableMock(spec=Connection, in_flight=0, is_defunct=False, is_closed=False, max_request_id=100,
                                      lock=Lock())
          session.cluster.connection_factory.return_value = conn
      
          pool = self.PoolImpl(host, HostDistance.LOCAL, session)
          session.cluster.connection_factory.assert_called_once_with(host.endpoint, on_orphaned_stream_released=pool.on_orphaned_stream_released)
      
          pool.borrow_connection(timeout=0.01)
          assert 1 == conn.in_flight
      
          def get_second_conn():
              c, request_id = pool.borrow_connection(1.0)
              assert conn is c
              pool.return_connection(c)
      
          t = Thread(target=get_second_conn)
          t.start()
      
  >       pool.return_connection(conn)
  
  /project/tests/unit/test_host_connection_pool.py:105: 
  _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
  
  self = <cassandra.pool.HostConnection object at 0x000000004310d948>
  connection = <HashableMock name='mock.cluster.connection_factory()' spec='Connection' id='1125178344'>
  stream_was_orphaned = False
  
      def return_connection(self, connection, stream_was_orphaned=False):
          if not stream_was_orphaned:
              with connection.lock:
                  connection.in_flight -= 1
              with self._stream_available_condition:
                  self._stream_available_condition.notify()
      
          if connection.is_defunct or connection.is_closed:
              if connection.signaled_error and not self.shutdown_on_error:
                  return
      
              is_down = False
              if not connection.signaled_error:
                  log.debug("Defunct or closed connection (%s) returned to pool, potentially "
                            "marking host %s as down", id(connection), self.host)
                  is_down = self.host.signal_connection_failure(connection.last_error)
                  connection.signaled_error = True
      
              if self.shutdown_on_error and not is_down:
                  is_down = True
      
              if is_down:
                  self.shutdown()
                  self._session.cluster.on_down(self.host, is_host_addition=False)
              else:
                  connection.close()
                  with self._lock:
                      if self.is_shutdown:
                          return
                      self._connections.pop(connection.features.shard_id, None)
                      if self._is_replacing:
                          return
                      self._is_replacing = True
                      self._session.submit(self._replace, connection)
  >       elif connection in self._trash:
               ^^^^^^^^^^^^^^^^^^^^^^^^^
  E       TypeError: __hash__ method should return an integer not 'MagicMock'

tests/unit/test_tcp_proxy.py, added in d99dc46, imported its subject
(TcpProxy) from tests/integration/standard/test_client_routes.py, which
transitively imports tests/integration/__init__.py. That module guards its
ccmlib imports with try/except ImportError, but then unconditionally
declares `class Cassandra41CCMCluster(CCMCluster)` at module level, so on
any environment without ccmlib installed the import fails with:

    NameError: name 'CCMCluster' is not defined

This broke test collection consistently on the windows-2022 job, where
ccmlib is absent. The latent defect in tests/integration/__init__.py
predates d99dc46; that commit merely became the first unit test to import
tests.integration and thus the first to expose it.

TcpProxy is a plain socket-based helper -- it depends only on socket,
select and threading, and needs neither CCM nor a running
Cassandra/Scylla cluster -- so it does not belong behind that import.
Move it verbatim into a new tests/tcp_proxy.py and import it from both
call sites:

- tests/integration/standard/test_client_routes.py now imports TcpProxy
  from tests.tcp_proxy; its `select` and `socket` imports, used only by
  the moved class, are dropped.
- tests/unit/test_tcp_proxy.py imports from tests.tcp_proxy and no longer
  needs its os.environ.setdefault("CASSANDRA_VERSION", ...) shim, which
  existed solely to get tests.integration's module-level version parsing
  to succeed. The shim and the docstring paragraph explaining it are
  removed.

The class body is byte-identical to the original; only the new module's
license header, docstring and imports are new. No driver code is touched
and no test behavior changes.

Validation:
- pytest tests/unit/test_tcp_proxy.py: 2 passed with neither
  CASSANDRA_VERSION nor SCYLLA_VERSION set, i.e. the unit test no longer
  imports tests.integration at all.
- tests/integration/standard/test_client_routes.py compiles clean with no
  imports left unused.

Fixes: scylladb#965
@dawmd

dawmd commented Aug 4, 2026

Copy link
Copy Markdown
Author

Sent an empty update to retrigger CI.

@coderabbitai
coderabbitai Bot requested a review from mykaul August 4, 2026 10:48
@dawmd

dawmd commented Aug 4, 2026

Copy link
Copy Markdown
Author

@scylladb/python-driver-maint please consider merging

@Lorak-mmk
Lorak-mmk merged commit a426787 into scylladb:master Aug 4, 2026
21 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.

tests/unit/test_tcp_proxy.py fails on windows-2022

3 participants