fix: repair imports lost in the 3.1 rebase and meet the new lint baseline

The rebase onto upstream 3.1 (mypy + ruff I001/F401 waves) left the tree
short of the newly enforced baselines in three ways:

* contextlib / UbridgeError imports dropped as false duplicates during
  conflict resolution left NameErrors in iou_vm and qemu_vm (F821);
  the Dynamips router grabbed the compute-level NIOTAP instead of the
  hypervisor one, breaking TAP anchoring (test failure).
* unused imports (KERNEL_UNSUPPORTED_FILTERS, UbridgeError, List) and
  unsorted blocks left behind where the stack's later commits moved the
  last usage elsewhere — ruff I001/F401/RUF022 now enforce these.
* mypy, now baseline-free: cache dict annotations in tc_probe, the
  locators candidate list, the resolved-params None branch in the MCP
  runner, and validate_bpf_syntax keeps the upstream Dict[str, Any]
  return (the strict Optional[str] was wrong for the "valid" bool entry).

The e2e raw-frame probe resolves its compiler via shutil.which (S607)
and zips with strict= (B905); the remaining subprocess call is S603 by
nature and gets a per-file ignore like other test files.

ruff check/format clean, mypy at upstream parity (no new errors),
full unit suite 2167 passed.
This commit is contained in:
YueGuobin committed 2026-10-06 00:21:11 +08:00
1 parent e13e5f3804
commit 7d04d08dba
35 files changed
+165 -136

No files matched your search

+6 -2
View File
@@ -246,7 +246,9 @@ class TestDuplicateDeviceMerging:
nornir = MagicMock()
nornir.run.return_value = _aggregated_result({"R1": "merged output"})
with (
patch(f"{CONFIG_MOD}.get_device_ports_from_topology", return_value={"R1": {"port": 5000, "node_type": "iou"}}),
patch(
f"{CONFIG_MOD}.get_device_ports_from_topology", return_value={"R1": {"port": 5000, "node_type": "iou"}}
),
patch.object(ExecuteMultipleDeviceConfigCommands, "_initialize_nornir", return_value=nornir),
):
result = ExecuteMultipleDeviceConfigCommands()._run(
@@ -310,7 +312,9 @@ class TestDuplicateDeviceMerging:
nornir = MagicMock()
nornir.run.return_value = _aggregated_result({"R1": "ok"})
with (
patch(f"{DISPLAY_MOD}.get_device_ports_from_topology", return_value={"R1": {"port": 5000, "node_type": "iou"}}),
patch(
f"{DISPLAY_MOD}.get_device_ports_from_topology", return_value={"R1": {"port": 5000, "node_type": "iou"}}
),
patch.object(ExecuteMultipleDeviceCommands, "_initialize_nornir", return_value=nornir),
patch(f"{DISPLAY_MOD}.filter_forbidden_commands", side_effect=fake_filter),
):
+13 -11
View File
@@ -69,8 +69,12 @@ def test_uuid_params_pass_through_without_calls():
def test_project_name_resolved():
"""A name-shaped project_id becomes the project's UUID."""
run, calls = _run_factory(projects=[{"project_id": "11111111-1111-1111-1111-111111111111", "name": "other"},
{"project_id": PROJECT_ID, "name": "my-lab"}])
run, calls = _run_factory(
projects=[
{"project_id": "11111111-1111-1111-1111-111111111111", "name": "other"},
{"project_id": PROJECT_ID, "name": "my-lab"},
]
)
params, error = resolve_locators({"project_id": "my-lab"}, run)
assert error is None
assert params["project_id"] == PROJECT_ID
@@ -88,8 +92,9 @@ def test_project_name_not_found_lists_known_names():
def test_node_name_resolved_within_project():
run, calls = _run_factory(projects=[{"project_id": PROJECT_ID, "name": "my-lab"}],
nodes=[{"node_id": NODE_ID, "name": "FRRDocker-4"}])
run, calls = _run_factory(
projects=[{"project_id": PROJECT_ID, "name": "my-lab"}], nodes=[{"node_id": NODE_ID, "name": "FRRDocker-4"}]
)
params, error = resolve_locators({"project_id": "my-lab", "node_id": "FRRDocker-4"}, run)
assert error is None
assert params["project_id"] == PROJECT_ID
@@ -125,11 +130,10 @@ def test_handler_failure_during_resolution_is_reported():
def test_did_you_mean_appended_for_transcription_slip():
"""The 2c9e -> 3b9e class of typo earns exactly one hint."""
run, _calls = _run_factory(projects=[{"project_id": PROJECT_ID, "name": "my-lab"}],
nodes=[{"node_id": NODE_ID, "name": "FRRDocker-4"}])
result = add_did_you_mean(
{"error": f"Node ID {NODE_ID_TYPO} doesn't exist"}, {"project_id": PROJECT_ID}, run
run, _calls = _run_factory(
projects=[{"project_id": PROJECT_ID, "name": "my-lab"}], nodes=[{"node_id": NODE_ID, "name": "FRRDocker-4"}]
)
result = add_did_you_mean({"error": f"Node ID {NODE_ID_TYPO} doesn't exist"}, {"project_id": PROJECT_ID}, run)
assert f"Did you mean node 'FRRDocker-4' ({NODE_ID})" in result["error"]
# original message preserved
assert NODE_ID_TYPO in result["error"]
@@ -144,9 +148,7 @@ def test_no_hint_when_too_far_or_ambiguous():
two = [NODE_ID, "b78a2630-2b9e-4b43-9397-c855c8053d1a"] # both within distance 2 of the typo
run2, _calls2 = _run_factory(nodes=[{"node_id": i, "name": f"n{i}"} for i in two])
result2 = add_did_you_mean(
{"error": f"Node ID {NODE_ID_TYPO} doesn't exist"}, {"project_id": PROJECT_ID}, run2
)
result2 = add_did_you_mean({"error": f"Node ID {NODE_ID_TYPO} doesn't exist"}, {"project_id": PROJECT_ID}, run2)
assert "Did you mean" not in result2["error"]
@@ -170,7 +170,9 @@ class TestCapabilitiesRoutes:
async def fake_bridge_tap_probe():
return True
monkeypatch.setattr("gns3server.api.routes.compute.capabilities.probe_bridge_tap_support", fake_bridge_tap_probe)
monkeypatch.setattr(
"gns3server.api.routes.compute.capabilities.probe_bridge_tap_support", fake_bridge_tap_probe
)
monkeypatch.setattr("gns3server.api.routes.compute.capabilities.probe_tap_support", _no_tap_probe)
monkeypatch.setattr("gns3server.api.routes.compute.capabilities.probe_iol_tap_support", _no_tap_probe)
response = await compute_client.get(app.url_path_for("compute:get_capabilities"))
@@ -23,23 +23,18 @@ fallback and cleanup.
import os
import uuid
from unittest.mock import MagicMock, call
from unittest.mock import MagicMock, call, patch
import pytest
import pytest_asyncio
from unittest.mock import patch
from tests.utils import AsyncioMagicMock
from gns3server.compute.docker import Docker
from gns3server.compute.docker.docker_vm import DockerVM
from gns3server.compute.docker.docker_error import DockerError, DockerHttp404Error
from gns3server.compute.compute_error import ComputeError
from gns3server.compute.nios.nio_udp import NIOUDP
from gns3server.compute.docker import Docker
from gns3server.compute.docker.docker_error import DockerError, DockerHttp404Error
from gns3server.compute.docker.docker_vm import DockerVM
from gns3server.compute.nios.nio_bridge import NIOBridge
from gns3server.compute.ubridge.ubridge_error import UbridgeError
from tests.utils import AsyncioMagicMock
BRIDGE = "gns3a1b2c3d4e5f"
@@ -1373,7 +1368,13 @@ def test_create_nio_udp_rejects_kernel_only_filters(vm):
with pytest.raises(ComputeError, match="kernel-datapath"):
vm.manager.create_nio(
{"type": "nio_udp", "lport": 4242, "rport": 4343, "rhost": "127.0.0.1", "filters": {"gemodel": [100, 0, 30]}}
{
"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1",
"filters": {"gemodel": [100, 0, 30]},
}
)
@@ -14,19 +14,15 @@ Image-free: everything is asserted against the uBridge command stream and
the anchor naming contract.
"""
import uuid
from unittest.mock import MagicMock, patch
import pytest
import pytest_asyncio
from unittest.mock import MagicMock, patch
from tests.utils import AsyncioMagicMock
from gns3server.compute.docker import Docker
from gns3server.compute.docker.docker_error import DockerError
from gns3server.compute.docker.iol_docker_vm import IOLDockerVM
from tests.utils import AsyncioMagicMock
NODE_ID = "00010203-0405-0607-0809-0a0b0c0d0e0f"
TAP00 = "gx00010203e0p0" # the vm fixture's node id, bay 0 unit 0
@@ -296,7 +292,9 @@ async def test_remove_nio_binding_kernel_releases_the_port_leg_first(vm):
commands = _commands(vm)
assert f"bridge stop {PORT_BRIDGE}" in commands
assert f'bridge delete_nio_tap {PORT_BRIDGE} "{TAP00}"' in commands
assert commands.index(f"bridge stop {PORT_BRIDGE}") < commands.index(f'bridge delete_nio_tap {PORT_BRIDGE} "{TAP00}"')
assert commands.index(f"bridge stop {PORT_BRIDGE}") < commands.index(
f'bridge delete_nio_tap {PORT_BRIDGE} "{TAP00}"'
)
assert f'tc reset "{TAP00}"' in commands
assert f'brctl delif "{BRIDGE}" "{TAP00}"' in commands
assert f'brctl delete "{BRIDGE}"' in commands
@@ -908,6 +908,7 @@ async def test_create_reparse_refreshes_env_knobs(compute_project, manager):
# Kernel-datapath (NIOBridge) rejection
# ---------------------------------------------------------------------------
@pytest.mark.asyncio
async def test_unix_socket_nio_rejects_kernel_datapath_link(compute_project, manager):
@@ -25,27 +25,24 @@ hypervisor's fds released before the TAPs are unpersisted — QEMU's order,
since here it is Dynamips that holds them).
"""
import contextlib
import os
import shutil
import contextlib
from unittest.mock import MagicMock, patch
import pytest
import pytest_asyncio
from unittest.mock import MagicMock, patch
from tests.utils import AsyncioMagicMock
from gns3server.compute.dynamips import Dynamips
from gns3server.compute.dynamips.nodes.router import Router
from gns3server.compute.dynamips.dynamips_error import DynamipsError
from gns3server.compute.dynamips.adapters.gt96100_fe import GT96100_FE
from gns3server.compute.dynamips.adapters.pa_4t import PA_4T
from gns3server.compute.dynamips.adapters.pa_fe_tx import PA_FE_TX
from gns3server.compute.dynamips.adapters.wic_1enet import WIC_1ENET
from gns3server.compute.ubridge.ubridge_error import UbridgeError
from gns3server.compute.dynamips.dynamips_error import DynamipsError
from gns3server.compute.dynamips.nodes.router import Router
from gns3server.compute.nios.nio_bridge import NIOBridge
from gns3server.compute.ubridge.ubridge_error import UbridgeError
from tests.utils import AsyncioMagicMock
NODE_ID = "00010203-0405-0607-0809-0a0b0c0d0e0f"
BRIDGE = "gns3a1b2c3d4e5f"
@@ -237,7 +234,7 @@ async def test_prepare_tap_datapath_wires_nios_bound_while_stopped(router):
hypervisor = _hypervisor_commands(router)
assert any(c.startswith("nio create_tap tap-") and c.endswith(f"{TAP00}") for c in hypervisor)
assert any(c.startswith(f"vm slot_add_nio_binding \"R1\" 0 0 tap-") for c in hypervisor)
assert any(c.startswith('vm slot_add_nio_binding "R1" 0 0 tap-') for c in hypervisor)
router._ubridge_send.assert_any_call(f'brctl addif "{BRIDGE}" "{TAP00}"')
assert (0, 0) in router._tap_nios
@@ -489,9 +486,7 @@ async def test_stop_ubridge_releases_hypervisor_fds_before_deleting_taps(router)
router._ubridge_send.reset_mock()
router._hypervisor.commands.clear()
with patch(
"gns3server.compute.base_node.BaseNode._stop_ubridge", new=AsyncioMagicMock()
) as stop:
with patch("gns3server.compute.base_node.BaseNode._stop_ubridge", new=AsyncioMagicMock()) as stop:
await router._stop_ubridge()
hypervisor = _hypervisor_commands(router)
@@ -22,19 +22,16 @@ it, kernel-link enslavement, the relay fallback for a uBridge without the
command, and the reverse-of-QEMU stop order (uBridge holds the anchor fds).
"""
from unittest.mock import MagicMock, patch
import pytest
import pytest_asyncio
from unittest.mock import MagicMock, patch
from tests.utils import AsyncioMagicMock
from gns3server.compute.iou import IOU
from gns3server.compute.iou.iou_vm import IOUVM
from gns3server.compute.iou.iou_error import IOUError
from gns3server.compute.nios.nio_bridge import NIOBridge
from gns3server.compute.iou.iou_vm import IOUVM
from gns3server.compute.ubridge.ubridge_error import UbridgeError
from tests.utils import AsyncioMagicMock
NODE_ID = "00010203-0405-0607-0809-0a0b0c0d0e0f"
BRIDGE = "gns3a1b2c3d4e5f"
@@ -24,21 +24,16 @@ legacy socket-netdev fallback for a uBridge without the tap module.
import asyncio
import os
import stat
import sys
from unittest.mock import MagicMock, patch
import pytest
import pytest_asyncio
from unittest.mock import MagicMock, patch
from tests.utils import asyncio_patch, AsyncioMagicMock
from gns3server.compute.qemu import Qemu
from gns3server.compute.qemu.qemu_vm import QemuVM
from gns3server.compute.qemu.qemu_error import QemuError
from gns3server.compute.nios.nio_bridge import NIOBridge
from gns3server.compute.qemu.qemu_vm import QemuVM
from gns3server.compute.ubridge.ubridge_error import UbridgeError
from tests.utils import AsyncioMagicMock, asyncio_patch
BRIDGE = "gns3a1b2c3d4e5f"
TAP0 = "gq00010203e0p0" # the vm fixture's node id, adapter 0
@@ -272,7 +267,7 @@ async def test_update_nio_binding_reapplies_filters_on_the_anchor(vm):
vm._ubridge_send.assert_any_call(f'tc reset "{TAP0}"')
vm._ubridge_send.assert_any_call(f'tc netem set "{TAP0}" delay 10')
assert not any(f"brctl addif" in str(c) for c in vm._ubridge_send.call_args_list)
assert not any("brctl addif" in str(c) for c in vm._ubridge_send.call_args_list)
@pytest.mark.asyncio
+2 -2
View File
@@ -25,8 +25,8 @@ from gns3server.compute.ubridge import tc_probe
from gns3server.compute.ubridge.tc_probe import (
probe_bridge_tap_support,
probe_iol_tap_support,
probe_tc_capabilities,
probe_tap_support,
probe_tc_capabilities,
)
from gns3server.compute.ubridge.ubridge_error import UbridgeError
@@ -65,7 +65,7 @@ class FakeHypervisor:
if self.error:
raise UbridgeError(self.error)
if self.error_prefix and command.startswith(self.error_prefix):
raise UbridgeError(f"202-Unknown command")
raise UbridgeError("202-Unknown command")
if command.startswith("bridge delete_nio_tap "):
if FakeHypervisor.bridge_tap_error:
raise UbridgeError(FakeHypervisor.bridge_tap_error)
+12 -1
View File
@@ -381,7 +381,18 @@ async def test_json(compute):
"disk_usage_percent": 0,
"connected": True,
"last_error": None,
"capabilities": {"version": "", "platform": "", "cpus": 0, "memory": 0, "disk_size": 0, "node_types": [], "ubridge_tc": None, "ubridge_tap": None, "ubridge_iol_tap": None, "ubridge_bridge_tap": None},
"capabilities": {
"version": "",
"platform": "",
"cpus": 0,
"memory": 0,
"disk_size": 0,
"node_types": [],
"ubridge_tc": None,
"ubridge_tap": None,
"ubridge_iol_tap": None,
"ubridge_bridge_tap": None,
},
}
assert compute.asdict(topology_dump=True) == {
"compute_id": "my_compute_id",
@@ -20,14 +20,15 @@ Controller-side kernel-datapath link selection: eligibility of Docker-to-
Docker links, NIO emission and the filters/markers guards.
"""
import pytest
from unittest.mock import MagicMock, patch
import pytest
from gns3server.config import Config
from gns3server.controller.udp_link import UDPLink
from gns3server.controller.ports.ethernet_port import EthernetPort
from gns3server.controller.node import Node
from gns3server.controller.controller_error import ControllerError
from gns3server.controller.node import Node
from gns3server.controller.ports.ethernet_port import EthernetPort
from gns3server.controller.udp_link import UDPLink
def _node(project, compute, name, node_type="docker", status="stopped", environment=None):
+3 -1
View File
@@ -903,7 +903,9 @@ class DockerDaemon:
)
response = conn.getresponse()
payload = response.read()
assert response.status == 200, f"docker cp into {container_id[:12]} -> HTTP {response.status}: {payload[:300]!r}"
assert response.status == 200, (
f"docker cp into {container_id[:12]} -> HTTP {response.status}: {payload[:300]!r}"
)
except (OSError, http.client.HTTPException) as e:
raise AssertionError(f"docker cp into {container_id[:12]} failed: {e}") from None
finally:
+8 -6
View File
@@ -47,6 +47,7 @@ The negative control for the old behaviour is the uBridge suite's
import functools
import io
import os
import shutil
import subprocess
import tarfile
import tempfile
@@ -246,9 +247,12 @@ def _llprobe():
binary = os.path.join(directory, "llprobe")
with open(source, "w") as f:
f.write(_LLPROBE_C)
cc = shutil.which("cc")
if cc is None:
pytest.skip("cannot build the raw-frame probe (no C compiler found)")
try:
subprocess.run(["cc", "-static", "-O2", "-o", binary, source], check=True, capture_output=True)
except (FileNotFoundError, subprocess.CalledProcessError) as e:
subprocess.run([cc, "-static", "-O2", "-o", binary, source], check=True, capture_output=True)
except subprocess.CalledProcessError as e:
pytest.skip(f"cannot build the raw-frame probe (cc -static): {e}")
return binary
@@ -270,9 +274,7 @@ def _upload_probe(daemon, *container_ids):
def _recv_counts(daemon, container_id, window, macs):
"""Run the receiver to completion and parse its "<mac>=<count>" lines."""
code, output = daemon.exec(
container_id, ["/tmp/llprobe", "recv", "eth0", str(window), *macs], timeout=window + 30
)
code, output = daemon.exec(container_id, ["/tmp/llprobe", "recv", "eth0", str(window), *macs], timeout=window + 30)
assert code == 0, output
return {line.split("=")[0]: int(line.split("=")[1]) for line in output.strip().splitlines() if "=" in line}
@@ -316,7 +318,7 @@ def test_docker_link_local_frames():
print(".. starting containers")
for node in nodes:
compute.call("POST", f"/projects/{pid}/nodes/{node['node_id']}/start")
for node, address in zip(nodes, (R1_IP, R2_IP)):
for node, address in zip(nodes, (R1_IP, R2_IP), strict=True):
harness.docker_wait_address(daemon, node["container_id"], address)
a1 = harness.docker_anchor_name(n1["node_id"], *ETH)