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.
Files changed (145) hide show
  1. {testprotocols-0.1.0/src/testprotocols.egg-info → testprotocols-0.2.0}/PKG-INFO +1 -1
  2. {testprotocols-0.1.0 → testprotocols-0.2.0}/pyproject.toml +1 -1
  3. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/__init__.py +0 -2
  4. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/appliance_vlans.py +15 -2
  5. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/devices/client.py +8 -0
  6. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/devices/sdwan.py +7 -1
  7. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/models/qoe.py +1 -0
  8. testprotocols-0.2.0/src/testprotocols/network_probe.py +49 -0
  9. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/qoe_browser.py +9 -1
  10. testprotocols-0.2.0/src/testprotocols/reachability_responder.py +55 -0
  11. {testprotocols-0.1.0 → testprotocols-0.2.0/src/testprotocols.egg-info}/PKG-INFO +1 -1
  12. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols.egg-info/SOURCES.txt +2 -1
  13. testprotocols-0.2.0/tests/test_appliance_vlans.py +33 -0
  14. {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_device_types.py +1 -0
  15. testprotocols-0.1.0/src/testprotocols/infra_controller.py +0 -28
  16. testprotocols-0.1.0/src/testprotocols/network_probe.py +0 -27
  17. {testprotocols-0.1.0 → testprotocols-0.2.0}/LICENSE +0 -0
  18. {testprotocols-0.1.0 → testprotocols-0.2.0}/NOTICE +0 -0
  19. {testprotocols-0.1.0 → testprotocols-0.2.0}/README.md +0 -0
  20. {testprotocols-0.1.0 → testprotocols-0.2.0}/setup.cfg +0 -0
  21. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/aftr_gateway.py +0 -0
  22. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/appliance_nat.py +0 -0
  23. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/appliance_uplinks.py +0 -0
  24. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/arp_client.py +0 -0
  25. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/bgp.py +0 -0
  26. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/conntrack.py +0 -0
  27. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/content_filtering.py +0 -0
  28. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/device_lifecycle.py +0 -0
  29. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/device_management.py +0 -0
  30. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/devices/__init__.py +0 -0
  31. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/devices/base.py +0 -0
  32. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/devices/cpe.py +0 -0
  33. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/devices/infra.py +0 -0
  34. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/devices/switch.py +0 -0
  35. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/devices/traffic.py +0 -0
  36. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/devices/voice.py +0 -0
  37. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/devices/wan.py +0 -0
  38. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/dhcp_client.py +0 -0
  39. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/dhcp_server.py +0 -0
  40. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/discovery.py +0 -0
  41. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/dns_client.py +0 -0
  42. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/file_transfer.py +0 -0
  43. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/firewall.py +0 -0
  44. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/firewall_zones.py +0 -0
  45. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/first_hop_security.py +0 -0
  46. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/gateway_redundancy.py +0 -0
  47. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/http_client.py +0 -0
  48. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/http_server.py +0 -0
  49. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/hw_console.py +0 -0
  50. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/interface_dhcp.py +0 -0
  51. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/ip_interface.py +0 -0
  52. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/ip_routing.py +0 -0
  53. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/iperf_client.py +0 -0
  54. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/iperf_generator.py +0 -0
  55. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/iperf_server.py +0 -0
  56. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/l3_firewall.py +0 -0
  57. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/l7_firewall.py +0 -0
  58. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/link_aggregation.py +0 -0
  59. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/mac_table.py +0 -0
  60. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/models/__init__.py +0 -0
  61. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/models/dhcp.py +0 -0
  62. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/models/firewall.py +0 -0
  63. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/models/impairment.py +0 -0
  64. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/models/l2_common.py +0 -0
  65. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/models/multicast.py +0 -0
  66. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/models/networking.py +0 -0
  67. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/models/packets.py +0 -0
  68. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/models/radius.py +0 -0
  69. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/models/sdwan_appliance.py +0 -0
  70. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/models/switch.py +0 -0
  71. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/models/switch_routing.py +0 -0
  72. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/models/tr069.py +0 -0
  73. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/models/traffic.py +0 -0
  74. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/models/wan_edge.py +0 -0
  75. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/models/wifi.py +0 -0
  76. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/multicast_client.py +0 -0
  77. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/nat.py +0 -0
  78. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/netem_controller.py +0 -0
  79. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/network_endpoint.py +0 -0
  80. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/nmap_scanner.py +0 -0
  81. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/ntp_client.py +0 -0
  82. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/ntp_config.py +0 -0
  83. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/ospf.py +0 -0
  84. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/packet_filter.py +0 -0
  85. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/pcap_capture.py +0 -0
  86. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/pdu_controller.py +0 -0
  87. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/port_poe.py +0 -0
  88. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/port_security.py +0 -0
  89. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/port_status.py +0 -0
  90. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/py.typed +0 -0
  91. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/radius_client.py +0 -0
  92. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/radius_server.py +0 -0
  93. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/routed_interfaces.py +0 -0
  94. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/router.py +0 -0
  95. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/routing_read.py +0 -0
  96. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/sdwan_policy_manager.py +0 -0
  97. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/sip_phone.py +0 -0
  98. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/sip_server.py +0 -0
  99. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/site_to_site_vpn.py +0 -0
  100. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/snmp_client.py +0 -0
  101. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/spanning_tree.py +0 -0
  102. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/static_routes.py +0 -0
  103. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/storm_control.py +0 -0
  104. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/streaming_server.py +0 -0
  105. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/switch_acl.py +0 -0
  106. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/switch_ports.py +0 -0
  107. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/switch_qos.py +0 -0
  108. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/switch_vlans.py +0 -0
  109. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/syslog_config.py +0 -0
  110. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/tftp_server.py +0 -0
  111. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/threat_prevention.py +0 -0
  112. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/tr069_client.py +0 -0
  113. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/tr069_server.py +0 -0
  114. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/traffic_shaping.py +0 -0
  115. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/upnp_client.py +0 -0
  116. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/vlan_client.py +0 -0
  117. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/wan_link_admin.py +0 -0
  118. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/wifi_bss.py +0 -0
  119. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/wifi_client.py +0 -0
  120. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/wifi_mesh.py +0 -0
  121. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/wifi_onboarding.py +0 -0
  122. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/wifi_radio.py +0 -0
  123. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/wifi_rf.py +0 -0
  124. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/wifi_stations.py +0 -0
  125. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols/wifi_transitions.py +0 -0
  126. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols.egg-info/dependency_links.txt +0 -0
  127. {testprotocols-0.1.0 → testprotocols-0.2.0}/src/testprotocols.egg-info/top_level.txt +0 -0
  128. {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_cpe_templates.py +0 -0
  129. {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_dhcp_templates.py +0 -0
  130. {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_firewall_templates.py +0 -0
  131. {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_infra_templates.py +0 -0
  132. {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_ip_interface.py +0 -0
  133. {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_ip_routing.py +0 -0
  134. {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_network_tool_templates.py +0 -0
  135. {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_package_imports.py +0 -0
  136. {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_radius_templates.py +0 -0
  137. {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_sdwan_appliance_models.py +0 -0
  138. {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_sdwan_appliance_templates.py +0 -0
  139. {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_switch_models.py +0 -0
  140. {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_switch_routing_models.py +0 -0
  141. {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_switch_templates.py +0 -0
  142. {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_traffic_templates.py +0 -0
  143. {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_voice_wifi_templates.py +0 -0
  144. {testprotocols-0.1.0 → testprotocols-0.2.0}/tests/test_wan_edge_templates.py +0 -0
  145. {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.1.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>
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "testprotocols"
3
- version = "0.1.0"
3
+ version = "0.2.0"
4
4
  description = "Common Test Resource Layer — capability and device protocols for telco testing."
5
5
  requires-python = ">=3.12"
6
6
  dependencies = []
@@ -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 DHCP
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)
@@ -29,3 +29,4 @@ class MeasurementSpec:
29
29
  completion: str = "networkidle"
30
30
  timeout_ms: int = 30000
31
31
  duration_s: int | None = None
32
+ force_quic: bool = True
@@ -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.1.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)
@@ -320,6 +320,7 @@ def test_qoe_measurement_client_aggregates_expected_capabilities() -> None:
320
320
  "iperf_client",
321
321
  "iperf_server",
322
322
  "network_probe",
323
+ "responder",
323
324
  "pcap",
324
325
  "syslog",
325
326
  }
@@ -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