testprotocols 0.1.0__tar.gz → 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {testprotocols-0.1.0/src/testprotocols.egg-info → testprotocols-0.2.0}/PKG-INFO +1 -1
- {testprotocols-0.1.0 → testprotocols-0.2.0}/pyproject.toml +1 -1
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/__init__.py +0 -2
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/appliance_vlans.py +15 -2
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/devices/client.py +8 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/devices/sdwan.py +7 -1
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/models/qoe.py +1 -0
- testprotocols-0.2.0/src/testprotocols/network_probe.py +49 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/qoe_browser.py +9 -1
- testprotocols-0.2.0/src/testprotocols/reachability_responder.py +55 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0/src/testprotocols.egg-info}/PKG-INFO +1 -1
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols.egg-info/SOURCES.txt +2 -1
- testprotocols-0.2.0/tests/test_appliance_vlans.py +33 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_device_types.py +1 -0
- testprotocols-0.1.0/src/testprotocols/infra_controller.py +0 -28
- testprotocols-0.1.0/src/testprotocols/network_probe.py +0 -27
- {testprotocols-0.1.0 → testprotocols-0.2.0}/LICENSE +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/NOTICE +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/README.md +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/setup.cfg +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/aftr_gateway.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/appliance_nat.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/appliance_uplinks.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/arp_client.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/bgp.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/conntrack.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/content_filtering.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/device_lifecycle.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/device_management.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/devices/__init__.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/devices/base.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/devices/cpe.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/devices/infra.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/devices/switch.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/devices/traffic.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/devices/voice.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/devices/wan.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/dhcp_client.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/dhcp_server.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/discovery.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/dns_client.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/file_transfer.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/firewall.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/firewall_zones.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/first_hop_security.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/gateway_redundancy.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/http_client.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/http_server.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/hw_console.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/interface_dhcp.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/ip_interface.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/ip_routing.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/iperf_client.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/iperf_generator.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/iperf_server.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/l3_firewall.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/l7_firewall.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/link_aggregation.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/mac_table.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/models/__init__.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/models/dhcp.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/models/firewall.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/models/impairment.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/models/l2_common.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/models/multicast.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/models/networking.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/models/packets.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/models/radius.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/models/sdwan_appliance.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/models/switch.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/models/switch_routing.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/models/tr069.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/models/traffic.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/models/wan_edge.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/models/wifi.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/multicast_client.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/nat.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/netem_controller.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/network_endpoint.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/nmap_scanner.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/ntp_client.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/ntp_config.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/ospf.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/packet_filter.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/pcap_capture.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/pdu_controller.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/port_poe.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/port_security.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/port_status.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/py.typed +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/radius_client.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/radius_server.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/routed_interfaces.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/router.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/routing_read.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/sdwan_policy_manager.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/sip_phone.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/sip_server.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/site_to_site_vpn.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/snmp_client.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/spanning_tree.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/static_routes.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/storm_control.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/streaming_server.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/switch_acl.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/switch_ports.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/switch_qos.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/switch_vlans.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/syslog_config.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/tftp_server.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/threat_prevention.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/tr069_client.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/tr069_server.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/traffic_shaping.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/upnp_client.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/vlan_client.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/wan_link_admin.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/wifi_bss.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/wifi_client.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/wifi_mesh.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/wifi_onboarding.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/wifi_radio.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/wifi_rf.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/wifi_stations.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/wifi_transitions.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols.egg-info/dependency_links.txt +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols.egg-info/top_level.txt +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_cpe_templates.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_dhcp_templates.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_firewall_templates.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_infra_templates.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_ip_interface.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_ip_routing.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_network_tool_templates.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_package_imports.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_radius_templates.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_sdwan_appliance_models.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_sdwan_appliance_templates.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_switch_models.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_switch_routing_models.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_switch_templates.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_traffic_templates.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_voice_wifi_templates.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_wan_edge_templates.py +0 -0
- {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_wifi_templates.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: testprotocols
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Common Test Resource Layer — capability and device protocols for telco testing.
|
|
5
5
|
Author-email: Alottabits <rjvisser@alottabits.com>
|
|
6
6
|
Maintainer-email: Alottabits <rjvisser@alottabits.com>
|
|
@@ -47,7 +47,6 @@ from testprotocols.gateway_redundancy import GatewayRedundancy
|
|
|
47
47
|
from testprotocols.http_client import HttpClient
|
|
48
48
|
from testprotocols.http_server import HttpServer
|
|
49
49
|
from testprotocols.hw_console import HwConsole
|
|
50
|
-
from testprotocols.infra_controller import InfraController
|
|
51
50
|
from testprotocols.interface_dhcp import InterfaceDhcp
|
|
52
51
|
from testprotocols.ip_interface import IpInterface
|
|
53
52
|
from testprotocols.ip_routing import IpRouting
|
|
@@ -136,7 +135,6 @@ __all__ = [
|
|
|
136
135
|
"HttpClient",
|
|
137
136
|
"HttpServer",
|
|
138
137
|
"HwConsole",
|
|
139
|
-
"InfraController",
|
|
140
138
|
"InterfaceDhcp",
|
|
141
139
|
"IpInterface",
|
|
142
140
|
"IpRouting",
|
|
@@ -5,8 +5,8 @@ subnet/addressing and DHCP configuration, plus observed DHCP leases. This is the
|
|
|
5
5
|
appliance counterpart to a Linux host's interface + DHCP-server surfaces — an
|
|
6
6
|
appliance configures DHCP per VLAN, not via a host daemon.
|
|
7
7
|
|
|
8
|
-
In scope: list/get/set VLAN configuration (incl. per-VLAN DHCP), and read
|
|
9
|
-
leases.
|
|
8
|
+
In scope: list/get/set/delete VLAN configuration (incl. per-VLAN DHCP), and read
|
|
9
|
+
DHCP leases.
|
|
10
10
|
|
|
11
11
|
Out of scope: WAN uplink status (see ``appliance_uplinks``), L3 firewall
|
|
12
12
|
(see ``l3_firewall``), and host-style per-interface config (see ``ip_interface``).
|
|
@@ -38,6 +38,19 @@ class ApplianceVlans(Protocol):
|
|
|
38
38
|
"""Create or replace the VLAN identified by ``config.vlan_id``."""
|
|
39
39
|
...
|
|
40
40
|
|
|
41
|
+
def delete_vlan(self, vlan_id: int) -> None:
|
|
42
|
+
"""Remove the LAN VLAN identified by *vlan_id*.
|
|
43
|
+
|
|
44
|
+
Per-object remove, completing the VLAN CRUD surface (mirrors
|
|
45
|
+
``StaticRoutes.remove_static_route``). On management planes that model the
|
|
46
|
+
LAN as one config blob, a driver implements this as read-modify-write of
|
|
47
|
+
that module. Deleting a missing VLAN may raise or succeed by plane;
|
|
48
|
+
callers needing idempotence should check first (``get_vlan`` raises
|
|
49
|
+
KeyError when absent). A plane that cannot remove a required / last LAN
|
|
50
|
+
VLAN raises unsupported-capability.
|
|
51
|
+
"""
|
|
52
|
+
...
|
|
53
|
+
|
|
41
54
|
def get_dhcp_leases(self, vlan_id: int | None = None) -> list[DhcpLease]:
|
|
42
55
|
"""Return current DHCP leases, optionally filtered to one *vlan_id*.
|
|
43
56
|
|
|
@@ -24,6 +24,7 @@ from testprotocols.ntp_client import NtpClient
|
|
|
24
24
|
from testprotocols.packet_filter import PacketFilter
|
|
25
25
|
from testprotocols.pcap_capture import PcapCapture
|
|
26
26
|
from testprotocols.qoe_browser import QoeBrowser
|
|
27
|
+
from testprotocols.reachability_responder import ReachabilityResponder
|
|
27
28
|
from testprotocols.syslog_config import SyslogConfig
|
|
28
29
|
from testprotocols.upnp_client import UpnpClient
|
|
29
30
|
from testprotocols.vlan_client import VlanClient
|
|
@@ -124,8 +125,15 @@ class QoeMeasurementClientDevice(QoeClientDevice, Protocol):
|
|
|
124
125
|
iperf_client: IperfClient
|
|
125
126
|
iperf_server: IperfServer
|
|
126
127
|
network_probe: NetworkProbe
|
|
128
|
+
responder: ReachabilityResponder
|
|
127
129
|
pcap: PcapCapture
|
|
128
130
|
|
|
131
|
+
test_ip: str
|
|
132
|
+
"""The client's test-plane address as a CIDR (e.g. ``"10.1.30.50/24"``), empty
|
|
133
|
+
if the client is not homed to a test segment. Vendor-neutral metadata the
|
|
134
|
+
driver resolves from its homing config — read it here rather than reaching into
|
|
135
|
+
a framework-specific config object."""
|
|
136
|
+
|
|
129
137
|
|
|
130
138
|
register_device_type("linux_lan_client", LanClientDevice)
|
|
131
139
|
register_device_type("linux_wlan_client", WlanClientDevice)
|
|
@@ -8,8 +8,8 @@ from testprotocols.appliance_nat import ApplianceNat
|
|
|
8
8
|
from testprotocols.appliance_uplinks import ApplianceUplinks
|
|
9
9
|
from testprotocols.appliance_vlans import ApplianceVlans
|
|
10
10
|
from testprotocols.bgp import Bgp
|
|
11
|
-
from testprotocols.content_filtering import ContentFiltering
|
|
12
11
|
from testprotocols.conntrack import Conntrack
|
|
12
|
+
from testprotocols.content_filtering import ContentFiltering
|
|
13
13
|
from testprotocols.devices import register_device_type
|
|
14
14
|
from testprotocols.devices.base import BaseDeviceProtocol
|
|
15
15
|
from testprotocols.ip_interface import IpInterface
|
|
@@ -93,5 +93,11 @@ class SdwanApplianceDevice(BaseDeviceProtocol, Protocol):
|
|
|
93
93
|
lan: ApplianceVlans
|
|
94
94
|
syslog: SyslogConfig
|
|
95
95
|
|
|
96
|
+
model: str
|
|
97
|
+
"""Hardware model identifier (e.g. ``"MX250"``) — vendor-neutral metadata the
|
|
98
|
+
driver resolves from its management API / inventory. The coverage axis for
|
|
99
|
+
model-parameterised tests; read it here rather than reaching into a
|
|
100
|
+
framework-specific config object."""
|
|
101
|
+
|
|
96
102
|
|
|
97
103
|
register_device_type("sdwan_appliance", SdwanApplianceDevice)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""Network reachability probe template.
|
|
2
|
+
|
|
3
|
+
Defines the abstract contract for L3/L4 reachability checks initiated from
|
|
4
|
+
a host toward an external target. Distinct from ``HttpClient`` (which is
|
|
5
|
+
app-layer): a ``NetworkProbe`` verifies whether the SYN/ACK handshake
|
|
6
|
+
completes, not whether an HTTP responder is configured at the far end.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from typing import Protocol, runtime_checkable
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@runtime_checkable
|
|
15
|
+
class NetworkProbe(Protocol):
|
|
16
|
+
"""Abstract contract for L3/L4 reachability probes."""
|
|
17
|
+
|
|
18
|
+
def tcp_can_connect(self, host: str, port: int, timeout: int = 5) -> bool:
|
|
19
|
+
"""Attempt a TCP connection to *host*:*port* and return reachability.
|
|
20
|
+
|
|
21
|
+
Returns ``True`` if the three-way handshake completes within
|
|
22
|
+
*timeout* seconds, ``False`` otherwise (connection refused, no
|
|
23
|
+
route, filtered, timed out). The probe is read-only — no data is
|
|
24
|
+
sent on the connection — so it is safe to call against arbitrary
|
|
25
|
+
targets without side effects on the destination.
|
|
26
|
+
"""
|
|
27
|
+
...
|
|
28
|
+
|
|
29
|
+
def icmp_can_reach(self, host: str, count: int = 1, timeout: int = 5) -> bool:
|
|
30
|
+
"""Attempt an ICMP echo to *host* and return reachability.
|
|
31
|
+
|
|
32
|
+
Returns ``True`` if at least one of *count* echo requests is answered
|
|
33
|
+
within *timeout* seconds, ``False`` otherwise (no route, filtered,
|
|
34
|
+
timed out). Read-only — echo requests have no side effect on the
|
|
35
|
+
destination.
|
|
36
|
+
"""
|
|
37
|
+
...
|
|
38
|
+
|
|
39
|
+
def udp_can_reach(self, host: str, port: int, timeout: int = 5) -> bool:
|
|
40
|
+
"""Attempt a UDP exchange with *host*:*port* and return reachability.
|
|
41
|
+
|
|
42
|
+
UDP is connectionless and has no handshake, so a dropped datagram is
|
|
43
|
+
indistinguishable from a delivered one at the sender unless the far end
|
|
44
|
+
replies. This probe therefore reports reachability based on a **reply**
|
|
45
|
+
from a UDP responder at the target within *timeout* seconds — callers
|
|
46
|
+
that need a definitive verdict must ensure a responder is present. A
|
|
47
|
+
missing reply (no responder, no route, or filtered) is ``False``.
|
|
48
|
+
"""
|
|
49
|
+
...
|
|
@@ -27,8 +27,16 @@ class QoeBrowser(Protocol):
|
|
|
27
27
|
scenario: str = "page_load",
|
|
28
28
|
wait_until: str = "networkidle",
|
|
29
29
|
timeout_ms: int = 30000,
|
|
30
|
+
force_quic: bool = True,
|
|
30
31
|
) -> QoEResult:
|
|
31
|
-
"""Measure productivity-app QoE for *url* (e.g., page-load time).
|
|
32
|
+
"""Measure productivity-app QoE for *url* (e.g., page-load time).
|
|
33
|
+
|
|
34
|
+
``force_quic=True`` (default) forces HTTP/3/QUIC, as a QoE measurement
|
|
35
|
+
should. Set ``force_quic=False`` for a reachability/block probe: the
|
|
36
|
+
navigation runs over TCP/h2 (QUIC disabled), so a non-HTTP/3 site stays
|
|
37
|
+
reachable and a TCP/TLS-inspecting middlebox (e.g. content filtering)
|
|
38
|
+
actually sees the traffic.
|
|
39
|
+
"""
|
|
32
40
|
...
|
|
33
41
|
|
|
34
42
|
def measure_streaming(
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""Reachability responder template — the answerer counterpart to ``NetworkProbe``.
|
|
2
|
+
|
|
3
|
+
``NetworkProbe`` *sends* reachability probes; a peer being probed must *answer*
|
|
4
|
+
them or a "blocked" verdict is indistinguishable from "no listener". This
|
|
5
|
+
capability stands up those answerers on the target's test interface:
|
|
6
|
+
|
|
7
|
+
* **TCP** — a listener that accepts connections (a ``tcp_can_connect`` connect
|
|
8
|
+
probe completes the handshake on accept).
|
|
9
|
+
* **UDP** — an echo responder (a content-based ``udp_can_reach`` probe sends a
|
|
10
|
+
token and is reachable iff it is echoed back).
|
|
11
|
+
|
|
12
|
+
ICMP needs no responder (the kernel answers echo requests). The pairing is
|
|
13
|
+
explicit and 1:1:
|
|
14
|
+
|
|
15
|
+
NetworkProbe.tcp_can_connect <-> ReachabilityResponder.start_tcp_responder
|
|
16
|
+
NetworkProbe.udp_can_reach <-> ReachabilityResponder.start_udp_responder
|
|
17
|
+
NetworkProbe.icmp_can_reach <-> (none — kernel)
|
|
18
|
+
|
|
19
|
+
Vendor-neutral contract; the listener mechanism (sockets / ``socat`` / a service)
|
|
20
|
+
lives entirely in the per-plugin impl, exactly as ``NetworkProbe`` impls do.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
from typing import Protocol, runtime_checkable
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@runtime_checkable
|
|
29
|
+
class ReachabilityResponder(Protocol):
|
|
30
|
+
"""Abstract contract for standing up / tearing down reachability responders."""
|
|
31
|
+
|
|
32
|
+
def start_tcp_responder(self, port: int) -> None:
|
|
33
|
+
"""Start a TCP responder on *port* that accepts connections.
|
|
34
|
+
|
|
35
|
+
A connect-only ``NetworkProbe.tcp_can_connect`` probe completes its
|
|
36
|
+
handshake against this listener, so an open path reads as reachable.
|
|
37
|
+
"""
|
|
38
|
+
...
|
|
39
|
+
|
|
40
|
+
def start_udp_responder(self, port: int) -> None:
|
|
41
|
+
"""Start a UDP echo responder on *port*.
|
|
42
|
+
|
|
43
|
+
Reflects every datagram it receives back to the sender, so a peer's
|
|
44
|
+
content-based ``NetworkProbe.udp_can_reach`` probe gets its token echoed
|
|
45
|
+
when the path is open — making "blocked" distinguishable from
|
|
46
|
+
"no listener" on the connectionless protocol.
|
|
47
|
+
"""
|
|
48
|
+
...
|
|
49
|
+
|
|
50
|
+
def stop(self, port: int | None = None) -> None:
|
|
51
|
+
"""Stop the responders on *port* (both protocols); ``None`` stops all.
|
|
52
|
+
|
|
53
|
+
No-op if none is running.
|
|
54
|
+
"""
|
|
55
|
+
...
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: testprotocols
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Common Test Resource Layer — capability and device protocols for telco testing.
|
|
5
5
|
Author-email: Alottabits <rjvisser@alottabits.com>
|
|
6
6
|
Maintainer-email: Alottabits <rjvisser@alottabits.com>
|
|
@@ -25,7 +25,6 @@ src/testprotocols/gateway_redundancy.py
|
|
|
25
25
|
src/testprotocols/http_client.py
|
|
26
26
|
src/testprotocols/http_server.py
|
|
27
27
|
src/testprotocols/hw_console.py
|
|
28
|
-
src/testprotocols/infra_controller.py
|
|
29
28
|
src/testprotocols/interface_dhcp.py
|
|
30
29
|
src/testprotocols/ip_interface.py
|
|
31
30
|
src/testprotocols/ip_routing.py
|
|
@@ -55,6 +54,7 @@ src/testprotocols/py.typed
|
|
|
55
54
|
src/testprotocols/qoe_browser.py
|
|
56
55
|
src/testprotocols/radius_client.py
|
|
57
56
|
src/testprotocols/radius_server.py
|
|
57
|
+
src/testprotocols/reachability_responder.py
|
|
58
58
|
src/testprotocols/routed_interfaces.py
|
|
59
59
|
src/testprotocols/router.py
|
|
60
60
|
src/testprotocols/routing_read.py
|
|
@@ -119,6 +119,7 @@ src/testprotocols/models/tr069.py
|
|
|
119
119
|
src/testprotocols/models/traffic.py
|
|
120
120
|
src/testprotocols/models/wan_edge.py
|
|
121
121
|
src/testprotocols/models/wifi.py
|
|
122
|
+
tests/test_appliance_vlans.py
|
|
122
123
|
tests/test_cpe_templates.py
|
|
123
124
|
tests/test_device_types.py
|
|
124
125
|
tests/test_dhcp_templates.py
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Protocol-conformance tests for ApplianceVlans (runtime_checkable structural check)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from testprotocols.appliance_vlans import ApplianceVlans
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class _Complete:
|
|
9
|
+
"""Has every ApplianceVlans member, including delete_vlan."""
|
|
10
|
+
|
|
11
|
+
def list_vlans(self): ...
|
|
12
|
+
def get_vlan(self, vlan_id): ...
|
|
13
|
+
def set_vlan(self, config): ...
|
|
14
|
+
def delete_vlan(self, vlan_id): ...
|
|
15
|
+
def get_dhcp_leases(self, vlan_id=None): ...
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class _NoDelete:
|
|
19
|
+
"""Missing delete_vlan — must NOT satisfy the protocol once delete_vlan is declared."""
|
|
20
|
+
|
|
21
|
+
def list_vlans(self): ...
|
|
22
|
+
def get_vlan(self, vlan_id): ...
|
|
23
|
+
def set_vlan(self, config): ...
|
|
24
|
+
def get_dhcp_leases(self, vlan_id=None): ...
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_complete_impl_satisfies_protocol():
|
|
28
|
+
assert isinstance(_Complete(), ApplianceVlans)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def test_delete_vlan_is_required_by_protocol():
|
|
32
|
+
# runtime_checkable isinstance requires every declared member be present.
|
|
33
|
+
assert not isinstance(_NoDelete(), ApplianceVlans)
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
"""Infra-controller capability template.
|
|
2
|
-
|
|
3
|
-
Abstract contract for environment/fabric control delegated by the test
|
|
4
|
-
orchestrator to a hypervisor (vSphere). It reads and (for re-homing) moves a
|
|
5
|
-
VM NIC's port-group, and asserts a named port-group is present. It does NOT
|
|
6
|
-
create fabric — the lab carries the test VLANs already.
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
from __future__ import annotations
|
|
10
|
-
|
|
11
|
-
from typing import Protocol, runtime_checkable
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
@runtime_checkable
|
|
15
|
-
class InfraController(Protocol):
|
|
16
|
-
"""Read / presence-check / move a VM NIC's port-group."""
|
|
17
|
-
|
|
18
|
-
def get_nic_portgroup(self, vm_name: str, nic_index: int) -> str:
|
|
19
|
-
"""Return the portgroup name backing NIC *nic_index* on *vm_name*."""
|
|
20
|
-
...
|
|
21
|
-
|
|
22
|
-
def ensure_port_group(self, name: str) -> None:
|
|
23
|
-
"""Assert a portgroup named *name* exists (raise if absent). No create."""
|
|
24
|
-
...
|
|
25
|
-
|
|
26
|
-
def set_nic_portgroup(self, vm_name: str, nic_index: int, portgroup: str) -> None:
|
|
27
|
-
"""Repoint NIC *nic_index* on *vm_name* onto the named *portgroup*."""
|
|
28
|
-
...
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
"""Network reachability probe template.
|
|
2
|
-
|
|
3
|
-
Defines the abstract contract for L3/L4 reachability checks initiated from
|
|
4
|
-
a host toward an external target. Distinct from ``HttpClient`` (which is
|
|
5
|
-
app-layer): a ``NetworkProbe`` verifies whether the SYN/ACK handshake
|
|
6
|
-
completes, not whether an HTTP responder is configured at the far end.
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
from __future__ import annotations
|
|
10
|
-
|
|
11
|
-
from typing import Protocol, runtime_checkable
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
@runtime_checkable
|
|
15
|
-
class NetworkProbe(Protocol):
|
|
16
|
-
"""Abstract contract for L3/L4 reachability probes."""
|
|
17
|
-
|
|
18
|
-
def tcp_can_connect(self, host: str, port: int, timeout: int = 5) -> bool:
|
|
19
|
-
"""Attempt a TCP connection to *host*:*port* and return reachability.
|
|
20
|
-
|
|
21
|
-
Returns ``True`` if the three-way handshake completes within
|
|
22
|
-
*timeout* seconds, ``False`` otherwise (connection refused, no
|
|
23
|
-
route, filtered, timed out). The probe is read-only — no data is
|
|
24
|
-
sent on the connection — so it is safe to call against arbitrary
|
|
25
|
-
targets without side effects on the destination.
|
|
26
|
-
"""
|
|
27
|
-
...
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|