testprotocols 0.5.0__tar.gz → 0.5.2__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.5.0/src/testprotocols.egg-info → testprotocols-0.5.2}/PKG-INFO +1 -1
- {testprotocols-0.5.0 → testprotocols-0.5.2}/pyproject.toml +1 -1
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/devices/client.py +8 -0
- testprotocols-0.5.2/src/testprotocols/dhcp_client.py +57 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/ip_interface.py +12 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/iperf_client.py +4 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/models/__init__.py +2 -1
- testprotocols-0.5.2/src/testprotocols/models/dhcp.py +65 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2/src/testprotocols.egg-info}/PKG-INFO +1 -1
- {testprotocols-0.5.0 → testprotocols-0.5.2}/tests/test_dhcp_templates.py +21 -1
- {testprotocols-0.5.0 → testprotocols-0.5.2}/tests/test_ip_interface.py +1 -0
- testprotocols-0.5.0/src/testprotocols/dhcp_client.py +0 -30
- testprotocols-0.5.0/src/testprotocols/models/dhcp.py +0 -28
- {testprotocols-0.5.0 → testprotocols-0.5.2}/LICENSE +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/NOTICE +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/README.md +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/setup.cfg +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/__init__.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/aftr_gateway.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/appliance_nat.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/appliance_uplinks.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/appliance_vlans.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/arp_client.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/bgp.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/conntrack.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/content_filtering.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/device_lifecycle.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/device_management.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/devices/__init__.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/devices/base.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/devices/cpe.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/devices/infra.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/devices/sdwan.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/devices/switch.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/devices/traffic.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/devices/voice.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/devices/wan.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/dhcp_server.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/discovery.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/dns_client.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/file_transfer.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/firewall.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/firewall_zones.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/first_hop_security.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/gateway_redundancy.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/http_client.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/http_server.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/hw_console.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/interface_dhcp.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/ip_routing.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/iperf_generator.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/iperf_server.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/l3_firewall.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/l7_firewall.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/link_aggregation.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/mac_table.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/models/firewall.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/models/impairment.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/models/l2_common.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/models/multicast.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/models/networking.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/models/packets.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/models/qoe.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/models/radius.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/models/sdwan_appliance.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/models/switch.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/models/switch_routing.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/models/tr069.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/models/traffic.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/models/wan_edge.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/models/wifi.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/multicast_client.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/nat.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/netem_controller.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/network_endpoint.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/network_probe.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/nmap_scanner.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/ntp_client.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/ntp_config.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/ospf.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/packet_filter.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/pcap_capture.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/pdu_controller.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/port_poe.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/port_security.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/port_status.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/py.typed +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/qoe_browser.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/radius_client.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/radius_server.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/reachability_responder.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/routed_interfaces.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/router.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/routing_read.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/sdwan_policy_manager.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/sip_phone.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/sip_server.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/site_to_site_vpn.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/snmp_client.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/spanning_tree.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/static_routes.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/storm_control.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/streaming_server.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/switch_acl.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/switch_ports.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/switch_qos.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/switch_vlans.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/syslog_config.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/tftp_server.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/threat_prevention.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/tr069_client.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/tr069_server.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/traffic_shaping.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/upnp_client.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/vlan_client.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/wan_link_admin.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/wifi_bss.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/wifi_client.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/wifi_mesh.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/wifi_onboarding.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/wifi_radio.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/wifi_rf.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/wifi_stations.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols/wifi_transitions.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols.egg-info/SOURCES.txt +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols.egg-info/dependency_links.txt +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/src/testprotocols.egg-info/top_level.txt +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/tests/test_appliance_vlans.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/tests/test_cpe_templates.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/tests/test_device_types.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/tests/test_firewall_templates.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/tests/test_infra_templates.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/tests/test_ip_routing.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/tests/test_network_tool_templates.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/tests/test_package_imports.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/tests/test_radius_templates.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/tests/test_sdwan_appliance_models.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/tests/test_sdwan_appliance_templates.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/tests/test_switch_models.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/tests/test_switch_routing_models.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/tests/test_switch_templates.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/tests/test_traffic_templates.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/tests/test_voice_wifi_templates.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/tests/test_wan_edge_templates.py +0 -0
- {testprotocols-0.5.0 → testprotocols-0.5.2}/tests/test_wifi_templates.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: testprotocols
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.2
|
|
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>
|
|
@@ -134,6 +134,14 @@ class QoeMeasurementClientDevice(QoeClientDevice, Protocol):
|
|
|
134
134
|
driver resolves from its homing config — read it here rather than reaching into
|
|
135
135
|
a framework-specific config object."""
|
|
136
136
|
|
|
137
|
+
attachment_segment: str
|
|
138
|
+
"""The declared segment LABEL of a guest-attached client (a client whose
|
|
139
|
+
test leg sits on a segment the testbed does not manage), empty for managed
|
|
140
|
+
homing or when undeclared. A stable role name (e.g. ``"provider-vpn"``),
|
|
141
|
+
never an address: it lets tests resolve "the client on segment X" by
|
|
142
|
+
declaration when address facts are foreign-owned or discovered late.
|
|
143
|
+
Vendor-neutral metadata from the driver's attachment config."""
|
|
144
|
+
|
|
137
145
|
|
|
138
146
|
register_device_type("linux_lan_client", LanClientDevice)
|
|
139
147
|
register_device_type("linux_wlan_client", WlanClientDevice)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""DHCP / Client template.
|
|
2
|
+
|
|
3
|
+
Defines the abstract contract for DHCP client operations including lease
|
|
4
|
+
release and renewal for both IPv4 and IPv6, and the scoped lease observation
|
|
5
|
+
that validates a served scope's option contents from the client side.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from collections.abc import Sequence
|
|
11
|
+
from typing import Protocol, runtime_checkable
|
|
12
|
+
|
|
13
|
+
from testprotocols.models.dhcp import DhcpLeaseObservation
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@runtime_checkable
|
|
17
|
+
class DhcpClient(Protocol):
|
|
18
|
+
"""Abstract contract for DHCP client operations."""
|
|
19
|
+
|
|
20
|
+
def release_dhcp(self, interface: str) -> None:
|
|
21
|
+
"""Release the DHCPv4 lease on *interface*."""
|
|
22
|
+
...
|
|
23
|
+
|
|
24
|
+
def renew_dhcp(self, interface: str) -> None:
|
|
25
|
+
"""Renew the DHCPv4 lease on *interface*."""
|
|
26
|
+
...
|
|
27
|
+
|
|
28
|
+
def release_ipv6(self, interface: str, stateless: bool = False) -> None:
|
|
29
|
+
"""Release the DHCPv6 lease on *interface*."""
|
|
30
|
+
...
|
|
31
|
+
|
|
32
|
+
def renew_ipv6(self, interface: str, stateless: bool = False) -> None:
|
|
33
|
+
"""Renew the DHCPv6 lease on *interface*."""
|
|
34
|
+
...
|
|
35
|
+
|
|
36
|
+
def observe_lease(
|
|
37
|
+
self, interface: str, request_options: Sequence[int] = ()
|
|
38
|
+
) -> DhcpLeaseObservation:
|
|
39
|
+
"""Obtain a fresh DHCPv4 lease on *interface* as a scoped observation.
|
|
40
|
+
|
|
41
|
+
Performs a full DHCP exchange that explicitly requests every option
|
|
42
|
+
code in *request_options* (on top of the core lease parameters — a
|
|
43
|
+
DHCP server only answers the options a client asks for), WITHOUT
|
|
44
|
+
altering the interface's configured addressing: the lease exists as
|
|
45
|
+
an observation record, not as interface state. Returns the received
|
|
46
|
+
lease with its raw option values. The caller closes the observation
|
|
47
|
+
with :meth:`release_observed_lease`. Raises if no lease is granted.
|
|
48
|
+
"""
|
|
49
|
+
...
|
|
50
|
+
|
|
51
|
+
def release_observed_lease(self, interface: str) -> None:
|
|
52
|
+
"""Release the lease obtained by :meth:`observe_lease` (idempotent).
|
|
53
|
+
|
|
54
|
+
Sends a DHCP release for the observed lease and discards the
|
|
55
|
+
observation record. A no-op when no observed lease is outstanding.
|
|
56
|
+
"""
|
|
57
|
+
...
|
|
@@ -37,6 +37,18 @@ class IpInterface(Protocol):
|
|
|
37
37
|
"""Return the MTU size of *interface*."""
|
|
38
38
|
...
|
|
39
39
|
|
|
40
|
+
def set_interface_mtu_size(self, interface: str, mtu: int) -> None:
|
|
41
|
+
"""Set the MTU of *interface* to *mtu* bytes.
|
|
42
|
+
|
|
43
|
+
The write counterpart to :meth:`get_interface_mtu_size`. Lowering the
|
|
44
|
+
MTU also lowers the MSS the host advertises on that interface, so it
|
|
45
|
+
governs TCP segment size in *both* directions of a flow — unlike a
|
|
46
|
+
per-socket ``TCP_MAXSEG``, which caps only the local send. Stateless
|
|
47
|
+
in contract: a caller that needs to revert captures the prior via
|
|
48
|
+
:meth:`get_interface_mtu_size` and restores it itself.
|
|
49
|
+
"""
|
|
50
|
+
...
|
|
51
|
+
|
|
40
52
|
def is_link_up(self, interface: str, pattern: str = "BROADCAST,MULTICAST,UP") -> bool:
|
|
41
53
|
"""Return True if *interface* flags match *pattern*."""
|
|
42
54
|
...
|
|
@@ -29,6 +29,7 @@ class IperfClient(Protocol):
|
|
|
29
29
|
omit_s: int | None = None,
|
|
30
30
|
json_output: bool = False,
|
|
31
31
|
window: str | None = None,
|
|
32
|
+
parallel: int | None = None,
|
|
32
33
|
) -> tuple[int, str]:
|
|
33
34
|
"""Start an iperf traffic sender towards *host* on *traffic_port*.
|
|
34
35
|
|
|
@@ -36,6 +37,9 @@ class IperfClient(Protocol):
|
|
|
36
37
|
|
|
37
38
|
- ``reverse``: iperf3 reverse mode (``-R``) — the listening receiver
|
|
38
39
|
transmits; the sender still initiates the connection.
|
|
40
|
+
- ``parallel``: run the session over N parallel streams (``-P <n>``).
|
|
41
|
+
The end-of-test ``sum``/``sum_received`` summaries aggregate across
|
|
42
|
+
the streams, so a multi-stream session reports ONE aggregate rate.
|
|
39
43
|
- ``omit_s``: skip the first N seconds (``-O <n>``, the TCP slow-start
|
|
40
44
|
ramp); omitted seconds extend the wall clock and are excluded from
|
|
41
45
|
the end-of-test summary.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from testprotocols.models.dhcp import DHCPTraceData, DHCPV6TraceData
|
|
5
|
+
from testprotocols.models.dhcp import DhcpLeaseObservation, DHCPTraceData, DHCPV6TraceData
|
|
6
6
|
from testprotocols.models.firewall import (
|
|
7
7
|
Connection,
|
|
8
8
|
ConntrackStats,
|
|
@@ -172,6 +172,7 @@ __all__ = [
|
|
|
172
172
|
# tr069
|
|
173
173
|
"CpeConnectionStatus",
|
|
174
174
|
# dhcp
|
|
175
|
+
"DhcpLeaseObservation",
|
|
175
176
|
"DHCPTraceData",
|
|
176
177
|
"DHCPV6TraceData",
|
|
177
178
|
"DhcpLease",
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""DHCP and DHCPv6 packet trace data models."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Mapping
|
|
6
|
+
from dataclasses import dataclass, field
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from testprotocols.models.networking import IPAddresses
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass(frozen=True)
|
|
13
|
+
class DhcpLeaseObservation:
|
|
14
|
+
"""A DHCPv4 lease obtained as a scoped observation, with its received options.
|
|
15
|
+
|
|
16
|
+
Produced by :meth:`testprotocols.dhcp_client.DhcpClient.observe_lease` —
|
|
17
|
+
the lease a server granted to a client that explicitly requested a set of
|
|
18
|
+
option codes, read from the client's own lease records (data-plane truth).
|
|
19
|
+
|
|
20
|
+
The typed fields surface the core lease parameters. ``options`` carries the
|
|
21
|
+
raw client-reported value string of every other option present in the
|
|
22
|
+
lease, keyed by option code, exactly as the client recorded it — no
|
|
23
|
+
normalization; value-comparison semantics belong to the caller.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
address: str
|
|
27
|
+
"""The leased IPv4 address (dotted quad)."""
|
|
28
|
+
|
|
29
|
+
subnet_mask: str = ""
|
|
30
|
+
"""Received subnet mask, option 1 (dotted quad; empty if absent)."""
|
|
31
|
+
|
|
32
|
+
gateway: str = ""
|
|
33
|
+
"""First received router, option 3 (dotted quad; empty if absent)."""
|
|
34
|
+
|
|
35
|
+
dns_servers: tuple[str, ...] = ()
|
|
36
|
+
"""Received DNS servers, option 6, in server order."""
|
|
37
|
+
|
|
38
|
+
lease_time_s: int = 0
|
|
39
|
+
"""Received lease time in seconds, option 51 (0 if absent)."""
|
|
40
|
+
|
|
41
|
+
server: str = ""
|
|
42
|
+
"""The DHCP server identifier, option 54 (dotted quad; empty if absent)."""
|
|
43
|
+
|
|
44
|
+
options: Mapping[int, str] = field(default_factory=dict)
|
|
45
|
+
"""Raw received value per option code, as reported by the client."""
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@dataclass
|
|
49
|
+
class DHCPTraceData:
|
|
50
|
+
"""Holds a captured DHCPv4 packet with source/destination addresses and message type."""
|
|
51
|
+
|
|
52
|
+
source: IPAddresses
|
|
53
|
+
destination: IPAddresses
|
|
54
|
+
dhcp_packet: dict[str, Any]
|
|
55
|
+
dhcp_message_type: int
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@dataclass
|
|
59
|
+
class DHCPV6TraceData:
|
|
60
|
+
"""Holds a captured DHCPv6 packet with source/destination addresses and message type."""
|
|
61
|
+
|
|
62
|
+
source: IPAddresses
|
|
63
|
+
destination: IPAddresses
|
|
64
|
+
dhcpv6_packet: dict[str, Any]
|
|
65
|
+
dhcpv6_message_type: int
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: testprotocols
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.2
|
|
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>
|
|
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
from testprotocols.dhcp_client import DhcpClient
|
|
6
6
|
from testprotocols.dhcp_server import DhcpServer
|
|
7
|
+
from testprotocols.models.dhcp import DhcpLeaseObservation
|
|
7
8
|
|
|
8
9
|
# ---------------------------------------------------------------------------
|
|
9
10
|
# DhcpClient
|
|
@@ -16,11 +17,30 @@ def test_dhcp_client_is_runtime_checkable() -> None:
|
|
|
16
17
|
|
|
17
18
|
def test_dhcp_client_protocol_shape() -> None:
|
|
18
19
|
"""DhcpClient declares the expected method set."""
|
|
19
|
-
expected = {
|
|
20
|
+
expected = {
|
|
21
|
+
"release_dhcp",
|
|
22
|
+
"renew_dhcp",
|
|
23
|
+
"release_ipv6",
|
|
24
|
+
"renew_ipv6",
|
|
25
|
+
"observe_lease",
|
|
26
|
+
"release_observed_lease",
|
|
27
|
+
}
|
|
20
28
|
actual = set(DhcpClient.__protocol_attrs__)
|
|
21
29
|
assert expected <= actual, f"missing: {expected - actual}"
|
|
22
30
|
|
|
23
31
|
|
|
32
|
+
def test_dhcp_lease_observation_defaults() -> None:
|
|
33
|
+
"""Only the address is mandatory; every other field has an empty default."""
|
|
34
|
+
obs = DhcpLeaseObservation(address="192.0.2.10")
|
|
35
|
+
assert obs.address == "192.0.2.10"
|
|
36
|
+
assert obs.subnet_mask == ""
|
|
37
|
+
assert obs.gateway == ""
|
|
38
|
+
assert obs.dns_servers == ()
|
|
39
|
+
assert obs.lease_time_s == 0
|
|
40
|
+
assert obs.server == ""
|
|
41
|
+
assert dict(obs.options) == {}
|
|
42
|
+
|
|
43
|
+
|
|
24
44
|
# ---------------------------------------------------------------------------
|
|
25
45
|
# DhcpServer
|
|
26
46
|
# ---------------------------------------------------------------------------
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
"""DHCP / Client template.
|
|
2
|
-
|
|
3
|
-
Defines the abstract contract for DHCP client operations including lease
|
|
4
|
-
release and renewal for both IPv4 and IPv6.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from __future__ import annotations
|
|
8
|
-
|
|
9
|
-
from typing import Protocol, runtime_checkable
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
@runtime_checkable
|
|
13
|
-
class DhcpClient(Protocol):
|
|
14
|
-
"""Abstract contract for DHCP client operations."""
|
|
15
|
-
|
|
16
|
-
def release_dhcp(self, interface: str) -> None:
|
|
17
|
-
"""Release the DHCPv4 lease on *interface*."""
|
|
18
|
-
...
|
|
19
|
-
|
|
20
|
-
def renew_dhcp(self, interface: str) -> None:
|
|
21
|
-
"""Renew the DHCPv4 lease on *interface*."""
|
|
22
|
-
...
|
|
23
|
-
|
|
24
|
-
def release_ipv6(self, interface: str, stateless: bool = False) -> None:
|
|
25
|
-
"""Release the DHCPv6 lease on *interface*."""
|
|
26
|
-
...
|
|
27
|
-
|
|
28
|
-
def renew_ipv6(self, interface: str, stateless: bool = False) -> None:
|
|
29
|
-
"""Renew the DHCPv6 lease on *interface*."""
|
|
30
|
-
...
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
"""DHCP and DHCPv6 packet trace data models."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
from dataclasses import dataclass
|
|
6
|
-
from typing import Any
|
|
7
|
-
|
|
8
|
-
from testprotocols.models.networking import IPAddresses
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@dataclass
|
|
12
|
-
class DHCPTraceData:
|
|
13
|
-
"""Holds a captured DHCPv4 packet with source/destination addresses and message type."""
|
|
14
|
-
|
|
15
|
-
source: IPAddresses
|
|
16
|
-
destination: IPAddresses
|
|
17
|
-
dhcp_packet: dict[str, Any]
|
|
18
|
-
dhcp_message_type: int
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
@dataclass
|
|
22
|
-
class DHCPV6TraceData:
|
|
23
|
-
"""Holds a captured DHCPv6 packet with source/destination addresses and message type."""
|
|
24
|
-
|
|
25
|
-
source: IPAddresses
|
|
26
|
-
destination: IPAddresses
|
|
27
|
-
dhcpv6_packet: dict[str, Any]
|
|
28
|
-
dhcpv6_message_type: int
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|