Skip to content

Conversation

@richtja
Copy link
Contributor

@richtja richtja commented Aug 6, 2025

This is a migration of network.ports utility from avocado.utils.path to AAutils.

Reference: #76,
https://github.com/avocado-framework/avocado/tree/master/avocado/utils/network

Summary by CodeRabbit

  • New Features

    • Added network port utilities to check availability, find free ports (sequential or random), and manage reserved ports via a shared tracker. Supports IPv4/IPv6 and TCP/UDP. Deprecated an older alias.
  • Documentation

    • Introduced a Network > Ports section and reorganized Path docs under File.
  • Tests

    • Added unit and functional tests covering port utilities and shared-state tracking.
  • Chores

    • Expanded test lint configuration and added module metadata (platforms, categorization, maintainer).

@richtja richtja requested review from clebergnu and harvey0100 August 6, 2025 10:07
@richtja richtja self-assigned this Aug 6, 2025
@coderabbitai
Copy link

coderabbitai bot commented Aug 6, 2025

Warning

Rate limit exceeded

@richtja has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 15 minutes and 52 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between db4483b and 016323c.

📒 Files selected for processing (6)
  • .pylintrc_tests (1 hunks)
  • autils/network/ports.py (1 hunks)
  • docs/source/utils.rst (1 hunks)
  • metadata/network/ports.yml (1 hunks)
  • tests/modules/network/ports_functional.py (1 hunks)
  • tests/modules/network/ports_unit.py (1 hunks)
📝 Walkthrough

Walkthrough

Adds a new network ports utility module with functions and a PortTracker class. Updates tests by adding unit and functional suites for the module. Adjusts docs to include the new network ports section and restructures some headings. Introduces metadata for the module. Expands disabled Pylint warnings for tests.

Changes

Cohort / File(s) Summary
Lint configuration
.\pylintrc_tests
Added disabled warnings: protected-access, too-many-lines, no-self-use in [MESSAGES CONTROL].
Network ports module
autils/network/ports.py
New module providing: is_port_available, deprecated is_port_free, find_free_port(s) with sequential/random search, and a Borg-pattern PortTracker for registering/releasing/free-port discovery.
Documentation
docs/source/utils.rst
Reorganized docs: added Network > Ports section for autils.network.ports; introduced File > Path; updated Archive subsection to Ar; removed prior Path under Archive.
Module metadata
metadata/network/ports.yml
New metadata describing the ports module, maintainers, platforms, and associated tests; marked remote: false.
Tests for ports
tests/modules/network/ports_unit.py, tests/modules/network/ports_functional.py
Added unit tests covering PortTracker behavior and port utility functions with mocks; added functional tests validating real socket behavior and Borg shared state.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

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

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@mr-avocado mr-avocado bot moved this to Review Requested in Default project Aug 6, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 17

🧹 Nitpick comments (10)
metadata/network.yml (1)

17-17: Potential typo in test filename.

The test filename appears to have a typo: network_funcional.py should likely be network_functional.py (missing 't').

-  - tests/modules/network/network_funcional.py
+  - tests/modules/network/network_functional.py
tests/modules/network/network_funcional.py (1)

87-89: Remove redundant skip decorator

The nested @unittest.skipUnless decorator is redundant since the entire class is already skipped when not running in CI. Additionally, /sys/class/net should always exist on Linux systems with networking support.

-    @unittest.skipUnless(
-        os.path.isdir("/sys/class/net"), "No network interfaces available"
-    )
     def test_localhost_interfaces(self):
autils/network/hosts.py (1)

165-167: Simplify return statement

The conditional return can be simplified to return the boolean result directly.

-        if re.search(check, mac_id):
-            return True
-        return False
+        return bool(re.search(check, mac_id))
tests/modules/network/network_unit.py (2)

212-212: Add comment to clarify intentional property access

These statements are intentionally accessing properties to test exception handling. Add a comment to clarify this is not a mistake.

-            local_host.interfaces  # pylint: disable=pointless-statement
+            # Intentionally access property to trigger exception
+            local_host.interfaces  # pylint: disable=pointless-statement

Also applies to: 357-357


96-110: Remove unused function get_all_local_addrs

This function is defined but never used in the test file. Consider removing it to reduce code clutter.

autils/network/interfaces.py (5)

216-218: Fix awkward f-string formatting

The f-string is split in a way that makes it harder to read.

-            raise NWException(
-                f"Slave interface not found for " f"the bond {self.name}"
-            ) from exc
+            raise NWException(
+                f"Slave interface not found for the bond {self.name}"
+            ) from exc

334-336: Fix f-string formatting

The f-string should be on a single line for better readability.

-        cmd = (
-            f"ip link add link {self.name} name {vlan_name} " f"type vlan id {vlan_num}"
-        )
+        cmd = f"ip link add link {self.name} name {vlan_name} type vlan id {vlan_num}"

845-847: Simplify return statement

Return the condition directly instead of using if/else.

-        if "l-lan" in output:
-            return True
-        return False
+        return "l-lan" in output

862-864: Simplify return statement

Return the condition directly instead of using if/else.

-        if "vnic" in output:
-            return True
-        return False
+        return "vnic" in output

879-882: Use any() for cleaner code

Replace the for loop with any() for a more Pythonic approach.

-        for vpd in output.split():
-            if "VF" in vpd and vpd.endswith("SN"):
-                return True
-        return False
+        return any("VF" in vpd and vpd.endswith("SN") for vpd in output.split())
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f297cfa and 13b47c6.

📒 Files selected for processing (10)
  • .pylintrc_tests (1 hunks)
  • autils/network/common.py (1 hunks)
  • autils/network/exceptions.py (1 hunks)
  • autils/network/hosts.py (1 hunks)
  • autils/network/interfaces.py (1 hunks)
  • autils/network/ports.py (1 hunks)
  • docs/source/utils.rst (1 hunks)
  • metadata/network.yml (1 hunks)
  • tests/modules/network/network_funcional.py (1 hunks)
  • tests/modules/network/network_unit.py (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
tests/modules/network/network_unit.py (5)
autils/network/hosts.py (9)
  • interfaces (70-90)
  • Host (33-190)
  • LocalHost (193-213)
  • get_interface_by_ipaddr (92-106)
  • get_interface_by_hwaddr (108-123)
  • get_all_hwaddr (125-145)
  • validate_mac_addr (148-167)
  • get_default_route_interface (169-190)
  • RemoteHost (216-322)
autils/network/ports.py (9)
  • PortTracker (156-221)
  • is_port_free (60-72)
  • register_port (179-193)
  • release_port (214-221)
  • _reset_retained_ports (175-177)
  • find_free_port (76-107)
  • find_free_port (195-212)
  • is_port_available (29-57)
  • find_free_ports (111-153)
autils/network/common.py (1)
  • run_command (11-38)
autils/network/exceptions.py (1)
  • NWException (9-10)
autils/network/interfaces.py (38)
  • get_ipaddrs (454-478)
  • get_hwaddr (480-494)
  • NetworkInterface (60-1080)
  • config_filename (90-117)
  • slave_config_filename (144-168)
  • _get_interface_details (170-196)
  • set_hwaddr (257-273)
  • bring_up (399-412)
  • bring_down (382-397)
  • get_mtu (496-509)
  • ping_check (511-532)
  • set_mtu (676-697)
  • validate_ipv4_format (953-976)
  • validate_ipv4_netmask_format (979-1015)
  • netmask_to_cidr (938-950)
  • add_ipaddr (275-295)
  • remove_ipaddr (699-720)
  • flush_ipaddr (722-738)
  • is_admin_link_up (414-427)
  • is_operational_link_up (429-442)
  • is_available (798-813)
  • is_bond (815-830)
  • is_link_up (444-452)
  • vlans (298-317)
  • add_vlan_tag (319-340)
  • remove_vlan_by_tag (342-365)
  • remove_all_vlans (367-380)
  • save (535-674)
  • are_packets_lost (906-935)
  • _get_bondinterface_details (198-218)
  • _move_file_to_backup (220-238)
  • remove_link (765-781)
  • nm_flush_ipaddr (740-763)
  • restore_from_backup (783-796)
  • restore_slave_cfg_file (889-904)
  • remove_cfg_file (884-887)
  • ping_flood (1018-1054)
  • get_device_IPI_name (1056-1080)
autils/network/interfaces.py (2)
autils/network/common.py (1)
  • run_command (11-38)
autils/network/exceptions.py (1)
  • NWException (9-10)
🪛 Ruff (0.12.2)
tests/modules/network/network_unit.py

132-135: Use a single with statement with multiple contexts instead of nested with statements

Combine with statements

(SIM117)


212-212: Found useless expression. Either assign it to a variable or remove it.

(B018)


357-357: Found useless expression. Either assign it to a variable or remove it.

(B018)


488-493: Use a single with statement with multiple contexts instead of nested with statements

Combine with statements

(SIM117)


531-534: Use a single with statement with multiple contexts instead of nested with statements

(SIM117)


642-647: Use a single with statement with multiple contexts instead of nested with statements

Combine with statements

(SIM117)


651-656: Use a single with statement with multiple contexts instead of nested with statements

Combine with statements

(SIM117)


906-909: Use a single with statement with multiple contexts instead of nested with statements

Combine with statements

(SIM117)


913-914: Use a single with statement with multiple contexts instead of nested with statements

(SIM117)

autils/network/ports.py

71-71: No explicit stacklevel keyword argument found

Set stacklevel=2

(B028)

autils/network/interfaces.py

845-847: Return the condition "l-lan" in output directly

Replace with return "l-lan" in output

(SIM103)


862-864: Return the condition "vnic" in output directly

Replace with return "vnic" in output

(SIM103)


879-882: Use return any("VF" in vpd and vpd.endswith("SN") for vpd in output.split()) instead of for loop

Replace with return any("VF" in vpd and vpd.endswith("SN") for vpd in output.split())

(SIM110)

autils/network/hosts.py

65-65: Use is and is not for type comparisons, or isinstance() for isinstance checks

(E721)


165-167: Return the condition bool(re.search(check, mac_id)) directly

Replace with return bool(re.search(check, mac_id))

(SIM103)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: api-stability-tests
  • GitHub Check: modules-tests
🔇 Additional comments (9)
.pylintrc_tests (1)

81-81: LGTM: Appropriate test configuration adjustment.

Disabling the protected-access warning for test code is a reasonable approach when testing internal behaviors of the new network utilities. This allows comprehensive testing without linting interruptions.

autils/network/exceptions.py (1)

1-11: LGTM: Well-designed exception hierarchy foundation.

The base exception class follows Python best practices with clear documentation and appropriate inheritance from Exception. This provides a solid foundation for network utility error handling.

docs/source/utils.rst (3)

4-6: LGTM: Appropriate documentation addition.

The new "Ar" subsection properly documents the archive utility module.


12-34: LGTM: Well-organized network utilities documentation.

The new "Network" section with its subsections (Common, Exceptions, Hosts, Interfaces, Ports) provides clear documentation structure for the network utilities modules. The Sphinx automodule directives are correctly formatted.


35-41: LGTM: Logical reorganization of path documentation.

Moving the path documentation under the "File" section provides better organizational structure and is more intuitive than the previous placement.

autils/network/common.py (1)

11-39: LGTM: Well-documented function with comprehensive interface.

The function provides a clean abstraction for command execution across local and remote hosts, with detailed documentation and consistent return types. The sudo support and error handling documentation are appropriate.

autils/network/hosts.py (2)

284-286: Review redundant connection logic in enter

The connection check and reconnection attempt seems redundant since _connect() is already called in __init__. If the connection fails in __init__, an exception is raised and the object isn't created. Consider if this reconnection logic is really needed.


65-66: Use isinstance() for type checking

Use isinstance() instead of direct type comparison for better practice and to handle inheritance properly.

-        if type(self) == Host:  # pylint: disable=C0123
+        if isinstance(self, type(self)):

Actually, the better approach here is:

-        if type(self) == Host:  # pylint: disable=C0123
+        if self.__class__ is Host:

Likely an incorrect or invalid review comment.

tests/modules/network/network_unit.py (1)

159-159: Import path for system_output is correct
The process module is brought in via from avocado.utils import process (e.g. in autils/network/interfaces.py and autils/network/common.py), so mocking avocado.utils.process.system_output matches the actual structure. No changes required.

@richtja richtja marked this pull request as draft August 6, 2025 12:15
@richtja richtja changed the title Introduction of network utility Introduction of network.ports utility Aug 6, 2025
@codecov
Copy link

codecov bot commented Aug 6, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (e493ff4) to head (016323c).
⚠️ Report is 22 commits behind head on main.

Additional details and impacted files
@@             Coverage Diff             @@
##           main       #88        +/-   ##
===========================================
+ Coverage      0   100.00%   +100.00%     
===========================================
  Files         0         1         +1     
  Lines         0        61        +61     
===========================================
+ Hits          0        61        +61     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@richtja richtja marked this pull request as ready for review August 6, 2025 13:33
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (3)
autils/network/ports.py (3)

71-71: Add stacklevel to deprecation warning

The deprecation warning is missing the stacklevel=2 parameter, causing it to point to this function instead of the caller's location.

-    warnings.warn("deprecated, use is_port_available() instead.", DeprecationWarning)
+    warnings.warn("deprecated, use is_port_available() instead.", DeprecationWarning, stacklevel=2)

189-189: Replace deprecated is_port_free with is_port_available

The PortTracker class still uses the deprecated is_port_free function internally, which should be replaced with is_port_available.

-        if (port not in self.retained_ports) and is_port_free(port, self.address):
+        if (port not in self.retained_ports) and is_port_available(port, self.address):

209-209: Replace deprecated is_port_free with is_port_available

The PortTracker class still uses the deprecated is_port_free function internally, which should be replaced with is_port_available.

-        while (port in self.retained_ports) or (not is_port_free(port, self.address)):
+        while (port in self.retained_ports) or (not is_port_available(port, self.address)):
🧹 Nitpick comments (1)
tests/modules/network/ports_unit.py (1)

105-111: Combine nested with statements for better readability

The nested with statements can be combined into a single statement as suggested by the static analysis tool.

 def test_is_port_free_deprecation_warning(self):
-    with self.assertWarns(DeprecationWarning):
-        with unittest.mock.patch(
-            "autils.network.ports.is_port_available"
-        ) as mock_is_port_available:
+    with (
+        self.assertWarns(DeprecationWarning),
+        unittest.mock.patch("autils.network.ports.is_port_available") as mock_is_port_available,
+    ):
             ports.is_port_free(22, "localhost")
             mock_is_port_available.assert_called_once_with(22, "localhost")
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 13b47c6 and c76d5a1.

📒 Files selected for processing (7)
  • .github/workflows/modules-tests.yml (1 hunks)
  • .pylintrc_tests (1 hunks)
  • autils/network/ports.py (1 hunks)
  • docs/source/utils.rst (1 hunks)
  • metadata/network/ports.yml (1 hunks)
  • tests/modules/network/ports_funcional.py (1 hunks)
  • tests/modules/network/ports_unit.py (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • metadata/network/ports.yml
  • .github/workflows/modules-tests.yml
🚧 Files skipped from review as they are similar to previous changes (2)
  • .pylintrc_tests
  • docs/source/utils.rst
🧰 Additional context used
🪛 Ruff (0.12.2)
tests/modules/network/ports_unit.py

106-109: Use a single with statement with multiple contexts instead of nested with statements

Combine with statements

(SIM117)

autils/network/ports.py

71-71: No explicit stacklevel keyword argument found

Set stacklevel=2

(B028)

🔇 Additional comments (9)
tests/modules/network/ports_funcional.py (3)

1-26: LGTM - Well-structured functional test setup

The module docstring clearly explains the purpose and scope of functional tests. The conditional skipping based on CI environment is appropriate for resource-intensive network tests.


28-54: LGTM - Comprehensive PortTracker functional tests

The test class effectively validates the core PortTracker functionality:

  • Port registration and release flow
  • Borg pattern shared state behavior
  • Proper test isolation with setUp method

The tests complement the unit tests by exercising real network operations.


56-81: LGTM - Effective utility function testing

The PortsTest class provides solid validation of the utility functions with real socket operations:

  • Confirms free ports can actually be bound to
  • Verifies bound ports are correctly detected as unavailable
  • Proper use of socket context manager for resource cleanup
tests/modules/network/ports_unit.py (1)

87-126: LGTM - Comprehensive utility function tests

The PortsTest class provides excellent coverage of the utility functions:

  • Tests normal operation and error conditions
  • Validates deprecation warning behavior
  • Uses appropriate mocking to isolate functionality
  • Good edge case coverage
autils/network/ports.py (5)

17-26: LGTM - Imports and constants properly defined

The Borg import path has been correctly updated from the past review, and the network constants are well-defined.


29-57: LGTM - Robust port availability checking

The function properly handles socket binding with appropriate exception handling for permission and OS errors. The implementation is correct and well-documented.


76-153: LGTM - Well-implemented port finding functions

Both functions are properly implemented with:

  • Comprehensive parameter documentation
  • Correct delegation pattern
  • Proper handling of sequential vs random search
  • Good use of the non-deprecated is_port_available function

156-177: LGTM - Proper Borg pattern implementation

The PortTracker class correctly implements the Borg pattern with:

  • Proper shared state initialization
  • Sensible default values
  • Clean string representation method
  • Conditional attribute initialization

214-221: LGTM - Clean port release implementation

The release_port method correctly removes ports from the retained list with proper existence checking.

@richtja richtja force-pushed the network_utility branch 2 times, most recently from a2a03fd to 9ca731a Compare August 6, 2025 13:55
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (4)
tests/modules/network/ports_unit.py (1)

34-40: Fix the mock setup in release_port test

The test is incorrectly mocking the method it's trying to test. This replaces tracker.release_port with a mock, so the assertion at line 39 just verifies the mock was called, not the actual method behavior.

 def test_release_port_does_not_poke_system(self):
     tracker = ports.PortTracker()
-    tracker.release_port = unittest.mock.MagicMock()
+    tracker.retained_ports = [22]
     ports.is_port_free = unittest.mock.MagicMock()
     tracker.release_port(22)
-    tracker.release_port.assert_called_once_with(22)
+    self.assertNotIn(22, tracker.retained_ports)
     ports.is_port_free.assert_not_called()
autils/network/ports.py (3)

71-71: Add stacklevel to deprecation warning

Include stacklevel=2 in the warning to show it at the caller's location rather than this function.

-    warnings.warn("deprecated, use is_port_available() instead.", DeprecationWarning)
+    warnings.warn("deprecated, use is_port_available() instead.", DeprecationWarning, stacklevel=2)

189-189: Replace deprecated is_port_free with is_port_available

The PortTracker class internally uses the deprecated is_port_free function. It should use is_port_available instead.

-        if (port not in self.retained_ports) and is_port_free(port, self.address):
+        if (port not in self.retained_ports) and is_port_available(port, self.address):

209-209: Replace deprecated is_port_free with is_port_available

The PortTracker class internally uses the deprecated is_port_free function. It should use is_port_available instead.

-        while (port in self.retained_ports) or (not is_port_free(port, self.address)):
+        while (port in self.retained_ports) or (not is_port_available(port, self.address)):
🧹 Nitpick comments (2)
tests/modules/network/ports_funcional.py (1)

15-15: Remove unused import

The os module is imported but never used in this file.

-import os
tests/modules/network/ports_unit.py (1)

106-111: Combine nested with statements

The nested with statements can be combined for better readability.

-        with self.assertWarns(DeprecationWarning):
-            with unittest.mock.patch(
-                "autils.network.ports.is_port_available"
-            ) as mock_is_port_available:
+        with self.assertWarns(DeprecationWarning), unittest.mock.patch(
+            "autils.network.ports.is_port_available"
+        ) as mock_is_port_available:
                 ports.is_port_free(22, "localhost")
                 mock_is_port_available.assert_called_once_with(22, "localhost")
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c76d5a1 and 9ca731a.

📒 Files selected for processing (6)
  • .pylintrc_tests (1 hunks)
  • autils/network/ports.py (1 hunks)
  • docs/source/utils.rst (1 hunks)
  • metadata/network/ports.yml (1 hunks)
  • tests/modules/network/ports_funcional.py (1 hunks)
  • tests/modules/network/ports_unit.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • .pylintrc_tests
  • docs/source/utils.rst
  • metadata/network/ports.yml
🧰 Additional context used
🪛 Ruff (0.12.2)
tests/modules/network/ports_funcional.py

15-15: os imported but unused

Remove unused import: os

(F401)

autils/network/ports.py

71-71: No explicit stacklevel keyword argument found

Set stacklevel=2

(B028)

tests/modules/network/ports_unit.py

106-109: Use a single with statement with multiple contexts instead of nested with statements

Combine with statements

(SIM117)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: api-stability-tests
  • GitHub Check: modules-tests
🔇 Additional comments (6)
tests/modules/network/ports_funcional.py (2)

22-47: LGTM - Well-structured functional tests

The PortTrackerTest class provides good coverage of the core functionality including port registration/release and the Borg pattern verification. The use of _reset_retained_ports() is appropriate for test isolation even though it accesses a private method.


49-69: LGTM - Comprehensive port availability testing

The PortsTest class effectively validates both positive and negative scenarios for port availability checking using real socket operations. The tests properly demonstrate that ports reported as free can actually be bound to.

tests/modules/network/ports_unit.py (2)

6-85: LGTM - Comprehensive unit test coverage

The PortTrackerTest class provides thorough testing of the PortTracker functionality including port registration, release, free port finding, and Borg pattern behavior. The use of mocks appropriately isolates the system calls.


87-126: LGTM - Good utility function testing

The PortsTest class effectively tests the standalone utility functions with proper error handling and deprecation warning verification.

autils/network/ports.py (2)

29-57: LGTM - Robust port availability checking

The is_port_available function properly handles both PermissionError and OSError exceptions, providing a reliable way to check port availability across different scenarios.


156-221: LGTM - Well-implemented PortTracker class

The PortTracker class correctly implements the Borg pattern for shared state management and provides a clean API for port tracking. The implementation properly handles port registration, finding free ports, and releasing ports.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (4)
tests/modules/network/ports_unit.py (1)

34-40: Fix the mock setup in release_port test

The test is incorrectly mocking the method it's trying to test. This replaces tracker.release_port with a mock, so the assertion at line 39 just verifies the mock was called, not the actual method behavior.

 def test_release_port_does_not_poke_system(self):
     tracker = ports.PortTracker()
-    tracker.release_port = unittest.mock.MagicMock()
+    tracker.retained_ports = [22]
     ports.is_port_free = unittest.mock.MagicMock()
     tracker.release_port(22)
-    tracker.release_port.assert_called_once_with(22)
+    self.assertNotIn(22, tracker.retained_ports)
     ports.is_port_free.assert_not_called()
autils/network/ports.py (3)

71-71: Add stacklevel to deprecation warning

Include stacklevel=2 in the warning to show it at the caller's location rather than this function.

-    warnings.warn("deprecated, use is_port_available() instead.", DeprecationWarning)
+    warnings.warn("deprecated, use is_port_available() instead.", DeprecationWarning, stacklevel=2)

189-189: Replace deprecated is_port_free with is_port_available

The PortTracker class internally uses the deprecated is_port_free function. It should use is_port_available instead.

-        if (port not in self.retained_ports) and is_port_free(port, self.address):
+        if (port not in self.retained_ports) and is_port_available(port, self.address):

209-209: Replace deprecated is_port_free with is_port_available

The PortTracker class internally uses the deprecated is_port_free function. It should use is_port_available instead.

-        while (port in self.retained_ports) or (not is_port_free(port, self.address)):
+        while (port in self.retained_ports) or (not is_port_available(port, self.address)):
🧹 Nitpick comments (1)
tests/modules/network/ports_unit.py (1)

105-111: Combine nested with statements for cleaner code.

The test logic is correct but can be simplified by combining the nested with statements.

     def test_is_port_free_deprecation_warning(self):
-        with self.assertWarns(DeprecationWarning):
-            with unittest.mock.patch(
-                "autils.network.ports.is_port_available"
-            ) as mock_is_port_available:
+        with (
+            self.assertWarns(DeprecationWarning),
+            unittest.mock.patch("autils.network.ports.is_port_available") as mock_is_port_available,
+        ):
                 ports.is_port_free(22, "localhost")
                 mock_is_port_available.assert_called_once_with(22, "localhost")
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9ca731a and d189b30.

📒 Files selected for processing (6)
  • .pylintrc_tests (1 hunks)
  • autils/network/ports.py (1 hunks)
  • docs/source/utils.rst (1 hunks)
  • metadata/network/ports.yml (1 hunks)
  • tests/modules/network/ports_funcional.py (1 hunks)
  • tests/modules/network/ports_unit.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • .pylintrc_tests
  • docs/source/utils.rst
  • tests/modules/network/ports_funcional.py
  • metadata/network/ports.yml
🧰 Additional context used
🪛 Ruff (0.12.2)
autils/network/ports.py

71-71: No explicit stacklevel keyword argument found

Set stacklevel=2

(B028)

tests/modules/network/ports_unit.py

106-109: Use a single with statement with multiple contexts instead of nested with statements

Combine with statements

(SIM117)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: modules-tests
  • GitHub Check: api-stability-tests
🔇 Additional comments (13)
tests/modules/network/ports_unit.py (8)

7-13: LGTM!

The test properly mocks the external dependency and verifies both the function call and state change.


15-27: LGTM!

Both error condition tests properly verify exception handling for ports in use and already retained ports.


28-32: LGTM!

The test correctly verifies that release_port removes the port from the retained list.


42-67: LGTM!

The find_free_port test methods comprehensively cover different scenarios including default behavior, explicit start port, and incrementing when ports are retained.


69-77: LGTM!

The test correctly verifies the Borg pattern behavior where multiple instances share state.


79-84: LGTM!

The test correctly verifies the string representation format of the PortTracker.


88-103: LGTM!

The is_port_available tests properly cover normal operation and error handling for both OSError and PermissionError exceptions.


113-125: LGTM!

The remaining test methods provide good coverage for find_free_port and find_free_ports functions, including edge cases like no available ports.

autils/network/ports.py (5)

17-26: LGTM!

The imports and constants are well-defined, and the Borg import path has been correctly updated.


29-57: LGTM!

The is_port_available function is well-implemented with proper error handling, resource management using context managers, and comprehensive documentation.


76-153: LGTM!

Both find_free_port and find_free_ports functions are well-implemented with comprehensive parameter handling, good documentation, and proper delegation to is_port_available.


156-178: LGTM!

The PortTracker class initialization and helper methods are well-implemented with proper Borg pattern usage and good documentation.


195-221: LGTM!

The find_free_port and release_port methods are well-implemented with proper logic for port management and good documentation.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (4)
autils/network/ports.py (3)

71-71: Add stacklevel to deprecation warning.

The deprecation warning should include stacklevel=2 to point to the caller's location rather than this function's location.

-    warnings.warn("deprecated, use is_port_available() instead.", DeprecationWarning)
+    warnings.warn("deprecated, use is_port_available() instead.", DeprecationWarning, stacklevel=2)

179-193: Fix usage of deprecated function in register_port.

The register_port method uses the deprecated is_port_free function instead of is_port_available.

-        if (port not in self.retained_ports) and is_port_free(port, self.address):
+        if (port not in self.retained_ports) and is_port_available(port, self.address):

195-212: Fix usage of deprecated function in find_free_port.

The find_free_port method uses the deprecated is_port_free function instead of is_port_available.

-        while (port in self.retained_ports) or (not is_port_free(port, self.address)):
+        while (port in self.retained_ports) or (not is_port_available(port, self.address)):
tests/modules/network/ports_unit.py (1)

34-41: Fix the mock setup in release_port test.

The test incorrectly mocks the method it's trying to test, which prevents testing the actual behavior.

 def test_release_port_does_not_poke_system(self):
     tracker = ports.PortTracker()
-    tracker.release_port = unittest.mock.MagicMock()
+    tracker.retained_ports = [22]
     ports.is_port_free = unittest.mock.MagicMock()
     tracker.release_port(22)
-    tracker.release_port.assert_called_once_with(22)
+    self.assertNotIn(22, tracker.retained_ports)
     ports.is_port_free.assert_not_called()
🧹 Nitpick comments (1)
tests/modules/network/ports_unit.py (1)

106-111: Consider simplifying nested with statements.

The nested with statements can be combined for better readability.

-    def test_is_port_free_deprecation_warning(self):
-        with self.assertWarns(DeprecationWarning):
-            with unittest.mock.patch(
-                "autils.network.ports.is_port_available"
-            ) as mock_is_port_available:
-                ports.is_port_free(22, "localhost")
-                mock_is_port_available.assert_called_once_with(22, "localhost")
+    def test_is_port_free_deprecation_warning(self):
+        with (
+            self.assertWarns(DeprecationWarning),
+            unittest.mock.patch(
+                "autils.network.ports.is_port_available"
+            ) as mock_is_port_available,
+        ):
+            ports.is_port_free(22, "localhost")
+            mock_is_port_available.assert_called_once_with(22, "localhost")
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d189b30 and 44a9625.

📒 Files selected for processing (6)
  • .pylintrc_tests (1 hunks)
  • autils/network/ports.py (1 hunks)
  • docs/source/utils.rst (1 hunks)
  • metadata/network/ports.yml (1 hunks)
  • tests/modules/network/ports_funcional.py (1 hunks)
  • tests/modules/network/ports_unit.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • .pylintrc_tests
  • docs/source/utils.rst
  • metadata/network/ports.yml
🧰 Additional context used
🧬 Code Graph Analysis (2)
tests/modules/network/ports_funcional.py (1)
autils/network/ports.py (6)
  • PortTracker (156-221)
  • _reset_retained_ports (175-177)
  • find_free_port (76-107)
  • find_free_port (195-212)
  • release_port (214-221)
  • is_port_available (29-57)
tests/modules/network/ports_unit.py (1)
autils/network/ports.py (9)
  • PortTracker (156-221)
  • is_port_free (60-72)
  • register_port (179-193)
  • release_port (214-221)
  • _reset_retained_ports (175-177)
  • find_free_port (76-107)
  • find_free_port (195-212)
  • is_port_available (29-57)
  • find_free_ports (111-153)
🪛 Ruff (0.12.2)
autils/network/ports.py

71-71: No explicit stacklevel keyword argument found

Set stacklevel=2

(B028)

tests/modules/network/ports_unit.py

106-109: Use a single with statement with multiple contexts instead of nested with statements

Combine with statements

(SIM117)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: api-stability-tests
  • GitHub Check: modules-tests
🔇 Additional comments (16)
autils/network/ports.py (6)

1-26: LGTM! Good module structure and documentation.

The file header, imports, and constants are well-organized. The module docstring clearly describes the purpose, and the defined families and protocols constants provide good reference points for the supported socket types.


29-57: LGTM! Robust port availability checking.

The is_port_available function correctly handles both PermissionError and OSError exceptions, providing a conservative approach by returning False when uncertain. The use of context manager ensures proper socket cleanup.


76-107: LGTM! Well-implemented port finding logic.

The find_free_port function properly delegates to find_free_ports and handles the case where no ports are found by returning None. The extensive parameter documentation is helpful.


111-153: LGTM! Efficient port range scanning.

The find_free_ports function implements a good strategy with optional randomization and early termination when enough ports are found. The logic is sound and well-documented.


156-178: LGTM! Proper Borg pattern implementation.

The PortTracker class correctly implements the Borg pattern with proper initialization and state management. The __str__ method provides useful debugging information.


214-221: LGTM! Clean port release implementation.

The release_port method properly removes the port from the retained list with appropriate safety checking.

tests/modules/network/ports_funcional.py (4)

1-19: LGTM! Excellent functional test documentation.

The module docstring clearly explains the purpose and scope of functional tests, distinguishing them from unit tests and explaining the rationale for testing real OS interactions.


21-46: LGTM! Well-designed PortTracker functional tests.

The tests properly validate the core PortTracker functionality:

  • Port registration and release with real state tracking
  • Borg pattern state sharing between instances
  • Proper cleanup in setUp method

The test logic is sound and tests real behavior without mocks.


48-68: LGTM! Effective port availability validation tests.

The tests validate real port behavior:

  • Actually binding to a port reported as free
  • Confirming that bound ports are reported as unavailable
  • Using OS-allocated ports (port 0) for reliable testing

The test design ensures real socket interactions are working correctly.


70-72: LGTM! Standard test runner setup.

The if __name__ == "__main__" block follows standard Python testing conventions.

tests/modules/network/ports_unit.py (6)

1-4: LGTM! Clean imports and setup.

The imports are minimal and appropriate for unit testing with mocks.


6-27: LGTM! Comprehensive PortTracker registration tests.

The tests properly validate:

  • Successful port registration when port is free
  • Failure when port is in use
  • Failure when port is already retained

The mock usage correctly isolates the unit under test.


28-33: LGTM! Simple and effective release test.

The test correctly validates that release_port removes the port from the retained list.


42-85: LGTM! Thorough PortTracker behavior tests.

The tests effectively validate:

  • Free port discovery starting from default and custom start ports
  • Port incrementing when retained ports exist
  • Borg pattern state sharing between instances
  • String representation functionality

The mock usage properly isolates dependencies while testing real behavior.


87-126: LGTM! Comprehensive port utility tests.

The tests properly validate:

  • Basic port availability checking
  • Error handling for OSError and PermissionError
  • Deprecation warning for is_port_free
  • Port finding functionality with edge cases

The mock usage correctly simulates various conditions.


128-130: LGTM! Standard test runner setup.

The if __name__ == "__main__" block follows standard Python testing conventions.

Copy link
Contributor

@clebergnu clebergnu left a comment

Choose a reason for hiding this comment

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

Hi @richtja,

There are a couple of typos and one wording suggestion. Other than that, it LGTM. I even tested the GDB code using this version of the library instead of avocado.utils.network.ports and it works great.

This is a migration of network.ports utility from
avocado.utils.network.ports to AAutils.

Reference: avocado-framework#76,
https://github.com/avocado-framework/avocado/blob/master/avocado/utils/network/ports.py
Signed-off-by: Jan Richter <jarichte@redhat.com>
Some pylint checks don't make sense in the terms of testing.

Signed-off-by: Jan Richter <jarichte@redhat.com>
@richtja richtja requested a review from clebergnu September 2, 2025 16:15
@clebergnu clebergnu merged commit 95c4893 into avocado-framework:main Sep 4, 2025
6 checks passed
@github-project-automation github-project-automation bot moved this from Review Requested to Done 112 in Default project Sep 4, 2025
richtja added a commit to richtja/avocado that referenced this pull request Sep 4, 2025
Since the network.ports development has been migrated to AAutils we need
to inform users and developers about this change.

Reference: avocado-framework/aautils#88
Signed-off-by: Jan Richter <jarichte@redhat.com>
richtja added a commit to richtja/avocado that referenced this pull request Sep 4, 2025
Since the network.ports development has been migrated to AAutils we need
to inform users and developers about this change.

Reference: avocado-framework/aautils#88
Signed-off-by: Jan Richter <jarichte@redhat.com>
maramsmurthy pushed a commit to maramsmurthy/avocado that referenced this pull request Nov 22, 2025
Since the network.ports development has been migrated to AAutils we need
to inform users and developers about this change.

Reference: avocado-framework/aautils#88
Signed-off-by: Jan Richter <jarichte@redhat.com>
xianglongfei-8888 pushed a commit to xianglongfei-8888/avocado that referenced this pull request Nov 25, 2025
Since the network.ports development has been migrated to AAutils we need
to inform users and developers about this change.

Reference: avocado-framework/aautils#88
Signed-off-by: Jan Richter <jarichte@redhat.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done 112

Development

Successfully merging this pull request may close these issues.

2 participants