testprotocols 0.1.0__py3-none-any.whl
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/__init__.py +217 -0
- testprotocols/aftr_gateway.py +22 -0
- testprotocols/appliance_nat.py +52 -0
- testprotocols/appliance_uplinks.py +32 -0
- testprotocols/appliance_vlans.py +50 -0
- testprotocols/arp_client.py +26 -0
- testprotocols/bgp.py +55 -0
- testprotocols/conntrack.py +147 -0
- testprotocols/content_filtering.py +47 -0
- testprotocols/device_lifecycle.py +49 -0
- testprotocols/device_management.py +50 -0
- testprotocols/devices/__init__.py +46 -0
- testprotocols/devices/base.py +40 -0
- testprotocols/devices/client.py +133 -0
- testprotocols/devices/cpe.py +66 -0
- testprotocols/devices/infra.py +62 -0
- testprotocols/devices/sdwan.py +97 -0
- testprotocols/devices/switch.py +115 -0
- testprotocols/devices/traffic.py +53 -0
- testprotocols/devices/voice.py +69 -0
- testprotocols/devices/wan.py +60 -0
- testprotocols/dhcp_client.py +30 -0
- testprotocols/dhcp_server.py +23 -0
- testprotocols/discovery.py +20 -0
- testprotocols/dns_client.py +23 -0
- testprotocols/file_transfer.py +22 -0
- testprotocols/firewall.py +121 -0
- testprotocols/firewall_zones.py +133 -0
- testprotocols/first_hop_security.py +52 -0
- testprotocols/gateway_redundancy.py +29 -0
- testprotocols/http_client.py +36 -0
- testprotocols/http_server.py +22 -0
- testprotocols/hw_console.py +48 -0
- testprotocols/infra_controller.py +28 -0
- testprotocols/interface_dhcp.py +30 -0
- testprotocols/ip_interface.py +62 -0
- testprotocols/ip_routing.py +57 -0
- testprotocols/iperf_client.py +47 -0
- testprotocols/iperf_generator.py +42 -0
- testprotocols/iperf_server.py +41 -0
- testprotocols/l3_firewall.py +74 -0
- testprotocols/l7_firewall.py +32 -0
- testprotocols/link_aggregation.py +24 -0
- testprotocols/mac_table.py +20 -0
- testprotocols/models/__init__.py +304 -0
- testprotocols/models/dhcp.py +28 -0
- testprotocols/models/firewall.py +197 -0
- testprotocols/models/impairment.py +18 -0
- testprotocols/models/l2_common.py +53 -0
- testprotocols/models/multicast.py +22 -0
- testprotocols/models/networking.py +50 -0
- testprotocols/models/packets.py +21 -0
- testprotocols/models/qoe.py +31 -0
- testprotocols/models/radius.py +63 -0
- testprotocols/models/sdwan_appliance.py +637 -0
- testprotocols/models/switch.py +297 -0
- testprotocols/models/switch_routing.py +122 -0
- testprotocols/models/tr069.py +35 -0
- testprotocols/models/traffic.py +29 -0
- testprotocols/models/wan_edge.py +116 -0
- testprotocols/models/wifi.py +183 -0
- testprotocols/multicast_client.py +20 -0
- testprotocols/nat.py +87 -0
- testprotocols/netem_controller.py +42 -0
- testprotocols/network_endpoint.py +32 -0
- testprotocols/network_probe.py +27 -0
- testprotocols/nmap_scanner.py +27 -0
- testprotocols/ntp_client.py +26 -0
- testprotocols/ntp_config.py +25 -0
- testprotocols/ospf.py +24 -0
- testprotocols/packet_filter.py +144 -0
- testprotocols/pcap_capture.py +39 -0
- testprotocols/pdu_controller.py +26 -0
- testprotocols/port_poe.py +25 -0
- testprotocols/port_security.py +25 -0
- testprotocols/port_status.py +23 -0
- testprotocols/py.typed +0 -0
- testprotocols/qoe_browser.py +62 -0
- testprotocols/radius_client.py +78 -0
- testprotocols/radius_server.py +130 -0
- testprotocols/routed_interfaces.py +29 -0
- testprotocols/router.py +53 -0
- testprotocols/routing_read.py +22 -0
- testprotocols/sdwan_policy_manager.py +64 -0
- testprotocols/sip_phone.py +230 -0
- testprotocols/sip_server.py +205 -0
- testprotocols/site_to_site_vpn.py +61 -0
- testprotocols/snmp_client.py +17 -0
- testprotocols/spanning_tree.py +37 -0
- testprotocols/static_routes.py +47 -0
- testprotocols/storm_control.py +24 -0
- testprotocols/streaming_server.py +32 -0
- testprotocols/switch_acl.py +29 -0
- testprotocols/switch_ports.py +28 -0
- testprotocols/switch_qos.py +33 -0
- testprotocols/switch_vlans.py +34 -0
- testprotocols/syslog_config.py +31 -0
- testprotocols/tftp_server.py +22 -0
- testprotocols/threat_prevention.py +60 -0
- testprotocols/tr069_client.py +47 -0
- testprotocols/tr069_server.py +151 -0
- testprotocols/traffic_shaping.py +54 -0
- testprotocols/upnp_client.py +37 -0
- testprotocols/vlan_client.py +22 -0
- testprotocols/wan_link_admin.py +34 -0
- testprotocols/wifi_bss.py +197 -0
- testprotocols/wifi_client.py +72 -0
- testprotocols/wifi_mesh.py +259 -0
- testprotocols/wifi_onboarding.py +105 -0
- testprotocols/wifi_radio.py +153 -0
- testprotocols/wifi_rf.py +78 -0
- testprotocols/wifi_stations.py +59 -0
- testprotocols/wifi_transitions.py +112 -0
- testprotocols-0.1.0.dist-info/METADATA +29 -0
- testprotocols-0.1.0.dist-info/RECORD +119 -0
- testprotocols-0.1.0.dist-info/WHEEL +5 -0
- testprotocols-0.1.0.dist-info/licenses/LICENSE +201 -0
- testprotocols-0.1.0.dist-info/licenses/NOTICE +11 -0
- testprotocols-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"""WiFi / WifiRadio template.
|
|
2
|
+
|
|
3
|
+
Defines the abstract contract for per-radio PHY control on a WiFi-capable
|
|
4
|
+
device (2.4 / 5 / 6 GHz radios). Covers admin state, channel / bandwidth /
|
|
5
|
+
tx power / mode configuration, regulatory-domain control, and DFS-state
|
|
6
|
+
read.
|
|
7
|
+
|
|
8
|
+
The template is per-device with band-keyed methods (matching the
|
|
9
|
+
existing palco pattern in IpInterface and WifiClient). A device with
|
|
10
|
+
multiple radios on the same band (e.g. dual-5GHz) is not modelled in
|
|
11
|
+
this release; band-string keying assumes one radio per band per device.
|
|
12
|
+
|
|
13
|
+
White-box extensions (radar-event injection, raw PHY dump) live on the
|
|
14
|
+
``WifiRadioWhiteBox`` extension Protocol below — see LEVELS.md for the
|
|
15
|
+
mandatory-vs-white-box rationale.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
from typing import Protocol, runtime_checkable
|
|
21
|
+
|
|
22
|
+
from testprotocols.models.wifi import WifiDfsState
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@runtime_checkable
|
|
26
|
+
class WifiRadio(Protocol):
|
|
27
|
+
"""Abstract contract for per-radio WiFi PHY control."""
|
|
28
|
+
|
|
29
|
+
# --- Discovery ---
|
|
30
|
+
|
|
31
|
+
def list_radios(self) -> list[str]:
|
|
32
|
+
"""Return the bands present on this device (e.g. ``["2.4GHz", "5GHz", "6GHz"]``)."""
|
|
33
|
+
...
|
|
34
|
+
|
|
35
|
+
# --- Admin state ---
|
|
36
|
+
|
|
37
|
+
def set_enabled(self, band: str, enabled: bool) -> None:
|
|
38
|
+
"""Enable or disable the radio on *band*. Disabling shuts down the PHY entirely."""
|
|
39
|
+
...
|
|
40
|
+
|
|
41
|
+
def get_enabled(self, band: str) -> bool:
|
|
42
|
+
"""Return True if the radio on *band* is administratively enabled."""
|
|
43
|
+
...
|
|
44
|
+
|
|
45
|
+
# --- Channel / bandwidth / power / mode ---
|
|
46
|
+
|
|
47
|
+
def set_channel(self, band: str, channel: int) -> None:
|
|
48
|
+
"""Set the operating channel on *band* to a specific channel number.
|
|
49
|
+
|
|
50
|
+
Auto-channel selection is not modelled in this release — pass an explicit
|
|
51
|
+
channel. Raises ValueError if *channel* is not in
|
|
52
|
+
``list_supported_channels(band)``.
|
|
53
|
+
"""
|
|
54
|
+
...
|
|
55
|
+
|
|
56
|
+
def get_channel(self, band: str) -> int:
|
|
57
|
+
"""Return the channel currently in use on *band*."""
|
|
58
|
+
...
|
|
59
|
+
|
|
60
|
+
def list_supported_channels(self, band: str) -> list[int]:
|
|
61
|
+
"""Return the channels the radio can operate on under the current regulatory domain."""
|
|
62
|
+
...
|
|
63
|
+
|
|
64
|
+
def set_bandwidth(self, band: str, bandwidth_mhz: int) -> None:
|
|
65
|
+
"""Set channel bandwidth on *band*: one of 20, 40, 80, 160, 320.
|
|
66
|
+
|
|
67
|
+
Raises ValueError if the radio does not support *bandwidth_mhz*
|
|
68
|
+
(e.g. 320 on a non-Wi-Fi-7 radio).
|
|
69
|
+
"""
|
|
70
|
+
...
|
|
71
|
+
|
|
72
|
+
def get_bandwidth(self, band: str) -> int:
|
|
73
|
+
"""Return the channel bandwidth currently in use on *band* (MHz)."""
|
|
74
|
+
...
|
|
75
|
+
|
|
76
|
+
def set_tx_power(self, band: str, power_dbm: int) -> None:
|
|
77
|
+
"""Set the transmit power on *band* in dBm.
|
|
78
|
+
|
|
79
|
+
Drivers translate to vendor units (percentage / index) internally.
|
|
80
|
+
Raises ValueError if *power_dbm* is outside the radio's supported range.
|
|
81
|
+
"""
|
|
82
|
+
...
|
|
83
|
+
|
|
84
|
+
def get_tx_power(self, band: str) -> int:
|
|
85
|
+
"""Return the transmit power currently in use on *band* (dBm)."""
|
|
86
|
+
...
|
|
87
|
+
|
|
88
|
+
def set_mode(self, band: str, mode: str) -> None:
|
|
89
|
+
"""Set the 802.11 PHY mode on *band*.
|
|
90
|
+
|
|
91
|
+
Values: ``"a"``, ``"b"``, ``"g"``, ``"n"``, ``"ac"``, ``"ax"``, ``"be"``.
|
|
92
|
+
Drivers may accept compound forms (``"n/ac/ax"``) at their discretion.
|
|
93
|
+
Raises ValueError if the radio does not support *mode*.
|
|
94
|
+
"""
|
|
95
|
+
...
|
|
96
|
+
|
|
97
|
+
def get_mode(self, band: str) -> str:
|
|
98
|
+
"""Return the 802.11 PHY mode currently in use on *band*."""
|
|
99
|
+
...
|
|
100
|
+
|
|
101
|
+
# --- Regulatory domain (device-wide) ---
|
|
102
|
+
|
|
103
|
+
def set_country(self, country_code: str) -> None:
|
|
104
|
+
"""Set the regulatory domain. *country_code* is ISO 3166-1 alpha-2 (``"US"``, ``"NL"``)."""
|
|
105
|
+
...
|
|
106
|
+
|
|
107
|
+
def get_country(self) -> str:
|
|
108
|
+
"""Return the configured regulatory domain as an ISO 3166-1 alpha-2 country code."""
|
|
109
|
+
...
|
|
110
|
+
|
|
111
|
+
# --- DFS ---
|
|
112
|
+
|
|
113
|
+
def get_dfs_state(self, band: str) -> WifiDfsState:
|
|
114
|
+
"""Return the current DFS state of the radio on *band*.
|
|
115
|
+
|
|
116
|
+
Includes Channel-Availability-Check status, time remaining, and
|
|
117
|
+
the Non-Occupancy List of channels currently locked out by prior
|
|
118
|
+
radar detection.
|
|
119
|
+
"""
|
|
120
|
+
...
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
@runtime_checkable
|
|
124
|
+
class WifiRadioWhiteBox(WifiRadio, Protocol):
|
|
125
|
+
"""White-box extension of WifiRadio for deep PHY introspection and event injection.
|
|
126
|
+
|
|
127
|
+
Drivers backed by ``mac80211_hwsim`` (OpenWrt with the simulator radio),
|
|
128
|
+
vendor PHY-test stacks, or simulated environments satisfy this extension.
|
|
129
|
+
Real APs typically satisfy only the base ``WifiRadio`` Protocol; tests
|
|
130
|
+
that need radar-event injection or raw PHY introspection should pin
|
|
131
|
+
against ``WifiRadioWhiteBox`` and accept that they collection-skip on
|
|
132
|
+
drivers that don't satisfy it (per the ``@white_box`` scenario tag rule).
|
|
133
|
+
"""
|
|
134
|
+
|
|
135
|
+
def inject_radar_event(self, band: str, channel: int | None = None) -> None:
|
|
136
|
+
"""Inject a synthetic radar detection event on *band*.
|
|
137
|
+
|
|
138
|
+
Test hook for DFS automation testing. *channel* defaults to the
|
|
139
|
+
radio's current channel. The OpenWrt + ``mac80211_hwsim`` driver
|
|
140
|
+
is the canonical implementer; drivers without hardware/simulation
|
|
141
|
+
support do not satisfy ``WifiRadioWhiteBox`` at all (rather than
|
|
142
|
+
raising at call time).
|
|
143
|
+
"""
|
|
144
|
+
...
|
|
145
|
+
|
|
146
|
+
def get_raw_phy_dump(self) -> str:
|
|
147
|
+
"""Dump raw nl80211 / vendor PHY state.
|
|
148
|
+
|
|
149
|
+
Returns the underlying driver's PHY description verbatim (e.g.
|
|
150
|
+
``iw phy`` output on Linux). Caller parses; format is driver-dependent
|
|
151
|
+
and intended for diagnostics, not for steady-state contract checks.
|
|
152
|
+
"""
|
|
153
|
+
...
|
testprotocols/wifi_rf.py
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""WiFi / WifiRf template.
|
|
2
|
+
|
|
3
|
+
Defines the abstract contract for per-radio RF observability:
|
|
4
|
+
on-demand scan triggering, neighbor BSS enumeration, channel utilization,
|
|
5
|
+
noise floor, and cumulative per-radio TX/RX/retry counters.
|
|
6
|
+
|
|
7
|
+
Read-only telemetry only — PHY configuration (channel, bandwidth, tx
|
|
8
|
+
power, mode, country, DFS state) lives in WifiRadio. Per-frame 802.11
|
|
9
|
+
spectrum analysis (FFT, CleanAir, spectral_scan) is deferred to a future
|
|
10
|
+
WifiSpectrum template, given the low cross-vendor uniformity.
|
|
11
|
+
|
|
12
|
+
Per-radio identity is band-keyed, matching WifiRadio.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from typing import Protocol, runtime_checkable
|
|
18
|
+
|
|
19
|
+
from testprotocols.models.wifi import (
|
|
20
|
+
WifiChannelUtilization,
|
|
21
|
+
WifiNeighbor,
|
|
22
|
+
WifiRadioStats,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@runtime_checkable
|
|
27
|
+
class WifiRf(Protocol):
|
|
28
|
+
"""Abstract contract for per-radio WiFi RF telemetry."""
|
|
29
|
+
|
|
30
|
+
# --- Scan ---
|
|
31
|
+
|
|
32
|
+
def scan(self, band: str, timeout: float = 30.0) -> list[WifiNeighbor]:
|
|
33
|
+
"""Trigger an off-channel scan on *band* and return the neighbour BSSes found.
|
|
34
|
+
|
|
35
|
+
Blocks until scan results are available or *timeout* seconds elapse.
|
|
36
|
+
Hides vendor divergence:
|
|
37
|
+
- Vendors that return immediately with a job handle: the driver polls
|
|
38
|
+
the job until it completes.
|
|
39
|
+
- Vendors that return inline: the driver returns directly.
|
|
40
|
+
- Vendors that post results to a separate diagnostic resource: the
|
|
41
|
+
driver polls that resource.
|
|
42
|
+
|
|
43
|
+
Raises TimeoutError if results are not available within *timeout*.
|
|
44
|
+
"""
|
|
45
|
+
...
|
|
46
|
+
|
|
47
|
+
def get_neighbors(self, band: str) -> list[WifiNeighbor]:
|
|
48
|
+
"""Return the most recent neighbour-BSS list for *band* without triggering a new scan.
|
|
49
|
+
|
|
50
|
+
Returns whatever the driver has cached from prior background scans
|
|
51
|
+
or the most recent ``scan()`` call. Empty list if no scan has run.
|
|
52
|
+
"""
|
|
53
|
+
...
|
|
54
|
+
|
|
55
|
+
# --- Channel telemetry ---
|
|
56
|
+
|
|
57
|
+
def get_channel_utilization(self, band: str) -> WifiChannelUtilization:
|
|
58
|
+
"""Return current channel utilization breakdown for *band*.
|
|
59
|
+
|
|
60
|
+
All percentages are 0-100. Drivers that don't separate TX/RX/interference
|
|
61
|
+
components return only ``busy_pct`` populated; the others are None.
|
|
62
|
+
"""
|
|
63
|
+
...
|
|
64
|
+
|
|
65
|
+
def get_noise_floor(self, band: str) -> int:
|
|
66
|
+
"""Return the current noise floor on *band* in dBm (typically negative, e.g. -95)."""
|
|
67
|
+
...
|
|
68
|
+
|
|
69
|
+
# --- Cumulative per-radio counters ---
|
|
70
|
+
|
|
71
|
+
def get_radio_stats(self, band: str) -> WifiRadioStats:
|
|
72
|
+
"""Return cumulative per-radio TX/RX/retry counters for *band*.
|
|
73
|
+
|
|
74
|
+
Counters are since the radio came up (typically boot or last
|
|
75
|
+
``WifiRadio.set_enabled(band, True)``). Drivers reset them on
|
|
76
|
+
radio disable/enable cycles.
|
|
77
|
+
"""
|
|
78
|
+
...
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""WiFi / WifiStations template.
|
|
2
|
+
|
|
3
|
+
Defines the abstract contract for the AP-side view of associated stations:
|
|
4
|
+
enumeration, per-station stats and capability inspection, and admin-driven
|
|
5
|
+
disconnect.
|
|
6
|
+
|
|
7
|
+
Stations are identified by MAC address. The MAC argument format is
|
|
8
|
+
free-form on input (drivers normalize); the canonical form returned in
|
|
9
|
+
read methods is lowercase colon-separated (e.g. "aa:bb:cc:dd:ee:ff").
|
|
10
|
+
|
|
11
|
+
Per-frame 802.11v BTM and 802.11k Neighbor-Report-Request operations
|
|
12
|
+
live on the WifiTransitions template, not here. This template only
|
|
13
|
+
covers admin-state operations on the AP's view of its stations.
|
|
14
|
+
|
|
15
|
+
Per-BSS MAC ACL administration (set_acl_mode, add_acl_entry, etc.)
|
|
16
|
+
lives on the WifiBss template — see SPLITS.md for the rationale.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
from typing import Protocol, runtime_checkable
|
|
22
|
+
|
|
23
|
+
from testprotocols.models.wifi import WifiStation
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@runtime_checkable
|
|
27
|
+
class WifiStations(Protocol):
|
|
28
|
+
"""Abstract contract for AP-side WiFi station inspection and admin."""
|
|
29
|
+
|
|
30
|
+
# --- Inspection ---
|
|
31
|
+
|
|
32
|
+
def list_associated_stations(self, bss_name: str | None = None) -> list[WifiStation]:
|
|
33
|
+
"""Return all currently associated stations, optionally filtered to *bss_name*.
|
|
34
|
+
|
|
35
|
+
With *bss_name* None, returns stations across all BSSes on the device.
|
|
36
|
+
Raises KeyError if *bss_name* is provided and not registered in WifiBss.
|
|
37
|
+
"""
|
|
38
|
+
...
|
|
39
|
+
|
|
40
|
+
def get_station(self, mac: str) -> WifiStation:
|
|
41
|
+
"""Return the full record for the associated station identified by *mac*.
|
|
42
|
+
|
|
43
|
+
Raises KeyError if no station with that MAC is currently associated.
|
|
44
|
+
"""
|
|
45
|
+
...
|
|
46
|
+
|
|
47
|
+
# --- Admin disconnect ---
|
|
48
|
+
|
|
49
|
+
def disconnect_station(self, mac: str, reason_code: int | None = None) -> None:
|
|
50
|
+
"""Administratively disconnect the station identified by *mac*.
|
|
51
|
+
|
|
52
|
+
*reason_code* is an optional IEEE 802.11 reason code (e.g. 1
|
|
53
|
+
"unspecified", 4 "disassociated due to inactivity"). When None the
|
|
54
|
+
driver picks a sensible default. This is admin-state disconnect —
|
|
55
|
+
for an explicit deauth frame use ``WifiTransitions.send_deauth``.
|
|
56
|
+
|
|
57
|
+
Raises KeyError if no station with that MAC is currently associated.
|
|
58
|
+
"""
|
|
59
|
+
...
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"""WiFi / WifiTransitions template.
|
|
2
|
+
|
|
3
|
+
Defines the abstract contract for IEEE 802.11k/v/r transition primitives
|
|
4
|
+
on a WiFi-capable device:
|
|
5
|
+
|
|
6
|
+
- Per-BSS admin enable for 802.11k (Radio Resource Management),
|
|
7
|
+
802.11v (BSS Transition Management), and 802.11r (Fast Transition).
|
|
8
|
+
- Per-client triggered frames: BTM Request (802.11v), Neighbor Report
|
|
9
|
+
Request (802.11k), explicit deauth.
|
|
10
|
+
|
|
11
|
+
802.11w (PMF) is set as a security parameter on WifiBss; reading it is
|
|
12
|
+
also done via WifiBss (no convenience-bleed snapshot here).
|
|
13
|
+
|
|
14
|
+
Per-client triggers may legitimately raise NotImplementedError on drivers
|
|
15
|
+
whose underlying stack only exposes coarse-grained "client steering"
|
|
16
|
+
features without raw frame-send (typical of controller-managed enterprise
|
|
17
|
+
stacks).
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
from typing import Protocol, runtime_checkable
|
|
23
|
+
|
|
24
|
+
from testprotocols.models.wifi import WifiTransitionConfig
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@runtime_checkable
|
|
28
|
+
class WifiTransitions(Protocol):
|
|
29
|
+
"""Abstract contract for 802.11 k/v/r admin and per-client transition primitives."""
|
|
30
|
+
|
|
31
|
+
# --- Per-BSS enables ---
|
|
32
|
+
|
|
33
|
+
def set_rrm_enabled(self, bss_name: str, enabled: bool) -> None:
|
|
34
|
+
"""Enable or disable 802.11k Radio Resource Management on *bss_name*.
|
|
35
|
+
|
|
36
|
+
Raises KeyError if *bss_name* is not registered.
|
|
37
|
+
"""
|
|
38
|
+
...
|
|
39
|
+
|
|
40
|
+
def set_btm_enabled(self, bss_name: str, enabled: bool) -> None:
|
|
41
|
+
"""Enable or disable 802.11v BSS Transition Management on *bss_name*.
|
|
42
|
+
|
|
43
|
+
Raises KeyError if *bss_name* is not registered.
|
|
44
|
+
"""
|
|
45
|
+
...
|
|
46
|
+
|
|
47
|
+
def set_ft_enabled(self, bss_name: str, enabled: bool, *, over_ds: bool = False) -> None:
|
|
48
|
+
"""Enable or disable 802.11r Fast Transition on *bss_name*.
|
|
49
|
+
|
|
50
|
+
*over_ds* controls FT-over-the-DS (True) vs FT-over-the-air (False).
|
|
51
|
+
Ignored when *enabled* is False.
|
|
52
|
+
Raises KeyError if *bss_name* is not registered.
|
|
53
|
+
"""
|
|
54
|
+
...
|
|
55
|
+
|
|
56
|
+
def get_transition_config(self, bss_name: str) -> WifiTransitionConfig:
|
|
57
|
+
"""Return the k/v/r configuration of *bss_name* (single read).
|
|
58
|
+
|
|
59
|
+
Raises KeyError if *bss_name* is not registered.
|
|
60
|
+
"""
|
|
61
|
+
...
|
|
62
|
+
|
|
63
|
+
# --- Per-client triggers ---
|
|
64
|
+
|
|
65
|
+
def send_btm_request(
|
|
66
|
+
self,
|
|
67
|
+
mac: str,
|
|
68
|
+
candidate_bssids: list[str] | None = None,
|
|
69
|
+
*,
|
|
70
|
+
disassoc_imminent: bool = False,
|
|
71
|
+
) -> None:
|
|
72
|
+
"""Send an 802.11v BSS Transition Management Request to the station *mac*.
|
|
73
|
+
|
|
74
|
+
*candidate_bssids* is an optional list of preferred candidate BSSIDs
|
|
75
|
+
for the client to consider roaming to (canonical lowercase
|
|
76
|
+
colon-separated). When None, the AP includes its default candidate set.
|
|
77
|
+
|
|
78
|
+
*disassoc_imminent* sets the "disassociation imminent" bit in the
|
|
79
|
+
request, prompting the client to roam faster on penalty of being
|
|
80
|
+
disassociated.
|
|
81
|
+
|
|
82
|
+
Raises KeyError if no station with that MAC is currently associated.
|
|
83
|
+
Drivers without raw BTM-frame support raise NotImplementedError.
|
|
84
|
+
"""
|
|
85
|
+
...
|
|
86
|
+
|
|
87
|
+
def send_neighbor_report_request(self, mac: str) -> None:
|
|
88
|
+
"""Send an 802.11k Neighbor Report Request to the station *mac*.
|
|
89
|
+
|
|
90
|
+
The client's response (a Neighbor Report containing BSSes it can see)
|
|
91
|
+
is consumed by the driver's internal neighbour table. Tests that
|
|
92
|
+
need the AP-side view of neighbours read it via
|
|
93
|
+
``WifiRf.get_neighbors``; the per-client client-side neighbour
|
|
94
|
+
report is not modelled in this release.
|
|
95
|
+
|
|
96
|
+
Raises KeyError if no station with that MAC is currently associated.
|
|
97
|
+
Drivers without raw 802.11k-NRR support raise NotImplementedError.
|
|
98
|
+
"""
|
|
99
|
+
...
|
|
100
|
+
|
|
101
|
+
def send_deauth(self, mac: str, reason_code: int = 2) -> None:
|
|
102
|
+
"""Send an explicit IEEE 802.11 Deauthentication frame to the station *mac*.
|
|
103
|
+
|
|
104
|
+
*reason_code* is an IEEE 802.11 reason code (default 2 — "previous
|
|
105
|
+
authentication no longer valid"). This is a raw-frame primitive,
|
|
106
|
+
distinct from ``WifiStations.disconnect_station`` which is admin-state
|
|
107
|
+
disconnect.
|
|
108
|
+
|
|
109
|
+
Raises KeyError if no station with that MAC is currently associated.
|
|
110
|
+
Drivers without raw deauth-frame support raise NotImplementedError.
|
|
111
|
+
"""
|
|
112
|
+
...
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: testprotocols
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Common Test Resource Layer — capability and device protocols for telco testing.
|
|
5
|
+
Author-email: Alottabits <rjvisser@alottabits.com>
|
|
6
|
+
Maintainer-email: Alottabits <rjvisser@alottabits.com>
|
|
7
|
+
License-Expression: Apache-2.0
|
|
8
|
+
Project-URL: Homepage, https://github.com/alottabits/testprotocols
|
|
9
|
+
Project-URL: Repository, https://github.com/alottabits/testprotocols
|
|
10
|
+
Project-URL: Issues, https://github.com/alottabits/testprotocols/issues
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Intended Audience :: Telecommunications Industry
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: Software Development :: Testing
|
|
18
|
+
Classifier: Typing :: Typed
|
|
19
|
+
Requires-Python: >=3.12
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
License-File: NOTICE
|
|
23
|
+
Dynamic: license-file
|
|
24
|
+
|
|
25
|
+
# testprotocols
|
|
26
|
+
|
|
27
|
+
Capability and device contracts as `typing.Protocol`s, plus their dataclass models. Pure stdlib, framework-neutral.
|
|
28
|
+
|
|
29
|
+
See the [monorepo README](../../README.md) for the full architecture.
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
testprotocols/__init__.py,sha256=lvF273gI4zv0uwudzrxxybmeM63-jSYACvEfkwCdHAg,7256
|
|
2
|
+
testprotocols/aftr_gateway.py,sha256=Zw70eyHTfeVjt3Y5D7-R71w3SB5RC86SESvWnjRhYLY,568
|
|
3
|
+
testprotocols/appliance_nat.py,sha256=lPtecOcM86-E5MFyq7ZhDC0X6Pn1B2NU0tMZZr3TPMI,1719
|
|
4
|
+
testprotocols/appliance_uplinks.py,sha256=x37O0ayGhuMSFr-J0LWPh9vgAUStWB1S0U0m_XOatMo,1072
|
|
5
|
+
testprotocols/appliance_vlans.py,sha256=oc7dNrMpuCdsA2T4lJ5dxmNzkqsBy3GBZc9_EPbEbbM,1811
|
|
6
|
+
testprotocols/arp_client.py,sha256=h5WEWqHj7TgTjUoz02GeudELmksHGKy76Ijid9_POyY,682
|
|
7
|
+
testprotocols/bgp.py,sha256=AvYL5Pck1MbzB5wplGEQb4MjC0VKQ6OhRy6Sg_fBFU0,2021
|
|
8
|
+
testprotocols/conntrack.py,sha256=HGyHoN6D7uDITQvG5e4U_juNThWtQgi35fdwc_eNnjw,4650
|
|
9
|
+
testprotocols/content_filtering.py,sha256=O-k5ln_PIukLHXSGs9z7tF_7cIKmdhUTUBF0kNV6V-k,1746
|
|
10
|
+
testprotocols/device_lifecycle.py,sha256=J97hSIJrqwAjmFCY99gI21WwhZwqvJRrCG5UIqpDVNA,1823
|
|
11
|
+
testprotocols/device_management.py,sha256=zPH8QSsst-2elfIqQtOO5HOuniSG5mftFVzi7mL0sws,1638
|
|
12
|
+
testprotocols/dhcp_client.py,sha256=IuvfPpHeu2x8uo0B5hme0OY7eOaWH8Js6xwwTMEzHVo,860
|
|
13
|
+
testprotocols/dhcp_server.py,sha256=0nX0Yx1Fi4g4Da_RnjBIFFYpHzC9dP1_UotEAxZ8iLw,557
|
|
14
|
+
testprotocols/discovery.py,sha256=CqvbmwyvCMnUBdPkEHNf5Sgo8k_0BOcKtoY_5xBjzf4,609
|
|
15
|
+
testprotocols/dns_client.py,sha256=1RqQSt_rT6osi-OIw-4ymb8nQFJSrWVNE3-MPuN1blI,550
|
|
16
|
+
testprotocols/file_transfer.py,sha256=YXkwRGaUz3Y_rVENZ9mLAteAo4mXDftKAQbRKq733UM,602
|
|
17
|
+
testprotocols/firewall.py,sha256=W9h6v7qbXs4FvzTiza9CGn-qRwMhd2y9owggSg3z-0U,4452
|
|
18
|
+
testprotocols/firewall_zones.py,sha256=2N1uca9zBQYIm0FK9gOarxldUQ5sNZDBpZ6H-69D5Lc,4355
|
|
19
|
+
testprotocols/first_hop_security.py,sha256=ai0Exebbr-Ttyc2FWaGkeO0QGYalGwvrkFaWqXZCIkU,2049
|
|
20
|
+
testprotocols/gateway_redundancy.py,sha256=iSMzUaSmB7STibsNYT5jcD-1pqpPO8LaY1uzgmCmVVg,908
|
|
21
|
+
testprotocols/http_client.py,sha256=us940z0C2OfG2gUp7EzCzTtfn_JG24_yNBTZoyRGlSY,854
|
|
22
|
+
testprotocols/http_server.py,sha256=dT-ook0zYrcnFCRVNhaF-YDjgpCjjLrVFrDW_aiXrUY,595
|
|
23
|
+
testprotocols/hw_console.py,sha256=a8A8cyIehni2Qn-lSNOm2NfytamO2Op4LAahkCa9qgU,1448
|
|
24
|
+
testprotocols/infra_controller.py,sha256=BYn_mO9KPOs-sO6IeZVK4n1AL7owJFmHkGrZZ8EWx1I,1016
|
|
25
|
+
testprotocols/interface_dhcp.py,sha256=94n3xYgzO44o8mLtOJ2H1r0cQujykcLg7G511wLpDjE,1095
|
|
26
|
+
testprotocols/ip_interface.py,sha256=cM5RNuz0iUpln6hK0k_zQhRJM7Vy2dO3wpr0Rj3R93Y,1959
|
|
27
|
+
testprotocols/ip_routing.py,sha256=MeA9OgkPA5lWwrN9ntShKUSBB1HVRsCEa_Zo1XDfJwo,1685
|
|
28
|
+
testprotocols/iperf_client.py,sha256=woPTHapGzfXWft2lwzOXk2hdmKrfhCjswhMs9ivm5Lg,1305
|
|
29
|
+
testprotocols/iperf_generator.py,sha256=x_DPhz8LO7ckCJNbLxE8OrqBlITJDDxo0WQKQyrK2-o,1296
|
|
30
|
+
testprotocols/iperf_server.py,sha256=HDr1yHVECSuVhL5rXpXJ0fw97yKUNUKR_rGY8TS7Chw,1107
|
|
31
|
+
testprotocols/l3_firewall.py,sha256=QYXYLko0Ul_lwB-Mwrou8ShZhCoxYM3NPeEDIgcGY00,2982
|
|
32
|
+
testprotocols/l7_firewall.py,sha256=V8H0kwjHceQw69f3nG5GUovLbI49RLvXsp4n9QOhCn8,1124
|
|
33
|
+
testprotocols/link_aggregation.py,sha256=91R4knkpBFMvRBdWd1F2eWeBwLE_x28vGe393AIqSVY,666
|
|
34
|
+
testprotocols/mac_table.py,sha256=hBy99JHxcmrCaAtqLZcwKktI3aanPVHeFRpdysQPSwk,613
|
|
35
|
+
testprotocols/multicast_client.py,sha256=oyP2T3L7jccDXlGuUPxCWekM-0kEsaX74mA0rgLsM3M,599
|
|
36
|
+
testprotocols/nat.py,sha256=yVqn7pK4QDhPyLkiYEXVE1ZdMbi7LOYzsPRzkRtCNLA,2924
|
|
37
|
+
testprotocols/netem_controller.py,sha256=7voR_knZoZuawTW43z_7kzb7gKTxkXNrOQFUv3-ZAT8,1454
|
|
38
|
+
testprotocols/network_endpoint.py,sha256=cyMgOqaamH1-YuLtNl2sHuyuQVA-6UMLg7dP5ZVEYgc,1202
|
|
39
|
+
testprotocols/network_probe.py,sha256=8Xcwtg_wqXAGn1GEaasaQzrukyyMV6Xbd69opMyOUBo,1058
|
|
40
|
+
testprotocols/nmap_scanner.py,sha256=R8e1rDpYYuJiiTd47v9gYVWkWNl7Dz0_Ux6ZQ53c6aQ,713
|
|
41
|
+
testprotocols/ntp_client.py,sha256=yXDxdLW69vR0KWFqdeEQ3UoagPL6AxG6glPF2Ct3q7I,751
|
|
42
|
+
testprotocols/ntp_config.py,sha256=zCsTgDNc3ov7H01FlzOtVbXlTPiiQVNNX-K15j1hiG0,757
|
|
43
|
+
testprotocols/ospf.py,sha256=1Tf9ZhWG8WQAgKXR1SYkyJ05MpFXYsRhPbhoWLBXFH4,633
|
|
44
|
+
testprotocols/packet_filter.py,sha256=T-2RGmmjNdZeIIyP-B-13vtgGedw7QMlF1h7ZqxjGZE,5154
|
|
45
|
+
testprotocols/pcap_capture.py,sha256=b3P3NTnuQDY8VDKqDbFPRKkcY6-1-ZFmQk1Qe6IEOHU,1063
|
|
46
|
+
testprotocols/pdu_controller.py,sha256=uW4lfaJmodhe3nh5HBL35AM_49gHhOlA9X1p3O53Zrg,664
|
|
47
|
+
testprotocols/port_poe.py,sha256=H8UHnkaboep7Iube2Ccigmebq256fqnfp9GMXMKQBXI,732
|
|
48
|
+
testprotocols/port_security.py,sha256=tayNi3hTkFICyUSQqZtaw9ya2RHQU4EgfT7A1Nx8GDk,742
|
|
49
|
+
testprotocols/port_status.py,sha256=2TcVSZxqpOHJV4vbkMxVnd-kWF9L7ga2bg7pVvv65rI,646
|
|
50
|
+
testprotocols/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
51
|
+
testprotocols/qoe_browser.py,sha256=Gp4J0BIzg5JEu1WoPM1uFVZs2GCaaO9c0Zxg5wtkrf4,1678
|
|
52
|
+
testprotocols/radius_client.py,sha256=HT6EiXzJQTPMHncHJDgeuibwzcQx386Z9chPZRyvbUo,2548
|
|
53
|
+
testprotocols/radius_server.py,sha256=potttcKVsy8Ju41jnZcpdzHvA5sH5cGMRbusv_hl-Nc,4474
|
|
54
|
+
testprotocols/routed_interfaces.py,sha256=hf75kNrYGoC37nlczk2CeJ4PkpPHyS_NhcGhNcK1kV0,942
|
|
55
|
+
testprotocols/router.py,sha256=qWWwMwNMQhNtBpGHcAbnVgprofYVpIfjkN6gXpV-uQk,1972
|
|
56
|
+
testprotocols/routing_read.py,sha256=uPSwrIF7sbABIldIbeK0_3jxHFtQHr5rz-DtA04sfEk,766
|
|
57
|
+
testprotocols/sdwan_policy_manager.py,sha256=7zbBedGTYZ3EJaFLoIO2X500w8HQUd66jLDcuqQREOg,2436
|
|
58
|
+
testprotocols/sip_phone.py,sha256=6qLankVypItcnYtyHQ2CEt9KP5p3-26ZxY9njBYNkPc,7155
|
|
59
|
+
testprotocols/sip_server.py,sha256=4Ww4iBUY5A9-QKJRv3eoRI15UAA0BxSomwrBd6knimw,7224
|
|
60
|
+
testprotocols/site_to_site_vpn.py,sha256=EfTq4nOZyaV3hyApkG53i_OLi4Zoe_RPJm5y5LtUJYw,2630
|
|
61
|
+
testprotocols/snmp_client.py,sha256=mutMvm4-oTZa_ZOI8oBmELQGpKTpU8kW85oVUI7NJP8,441
|
|
62
|
+
testprotocols/spanning_tree.py,sha256=SO57rydMW3KZOpZqvkNPd7UeXQU9xKusn-xhnocR3Lo,1222
|
|
63
|
+
testprotocols/static_routes.py,sha256=K4-wmClBPuRuIB_Y2W9qZCjkK56R0XjEjqu2seYbdxk,1646
|
|
64
|
+
testprotocols/storm_control.py,sha256=aukzvk5io18Yfl27BCBB9FcDfslCwa84LN1YL3PfPsg,714
|
|
65
|
+
testprotocols/streaming_server.py,sha256=_LBGejTCiVD6pX6QOzh_B1JvXml-szotXzSAa30cfy0,1105
|
|
66
|
+
testprotocols/switch_acl.py,sha256=rBVxkkny--m3ahoJu6H3x-UoD0IUxrp3UmvS6mWfevM,1044
|
|
67
|
+
testprotocols/switch_ports.py,sha256=J8Gn1gbsHbCX4aThnEgsOKyz5S3GmSxdPpx0_8OtOYU,851
|
|
68
|
+
testprotocols/switch_qos.py,sha256=Y4wThfzjQBfv5-wj94tYvgYA51uIfwNMhTVeLtLkv80,974
|
|
69
|
+
testprotocols/switch_vlans.py,sha256=Yeca82V7aT0cMJI8pExMyEwHWkUuhAJ5-38SgWy-1fQ,1068
|
|
70
|
+
testprotocols/syslog_config.py,sha256=1EY4BQjePbBBOORovmEncv2o9yQvyWtxWa3UletP-LE,1119
|
|
71
|
+
testprotocols/tftp_server.py,sha256=8tS65johIZ6kSOLWanyoE0cSMeNvGOVItRtzzB0RoCc,603
|
|
72
|
+
testprotocols/threat_prevention.py,sha256=tWxulxIxRE6w3MXnPjxzMIf4zG8G4k4p7Ilk2T86FaA,2011
|
|
73
|
+
testprotocols/tr069_client.py,sha256=FsTqefxFFcIIWgqscjqSAL4yDykSOTq_iVTn2VJZeHk,1771
|
|
74
|
+
testprotocols/tr069_server.py,sha256=sHe6dEigPVobOW-Txh2TI72CZatm8ef0yU1SDmSQBGs,4036
|
|
75
|
+
testprotocols/traffic_shaping.py,sha256=BXKUd4pQt4zsOUqCT3Cg22koVbT3r3EFjaTDqvykXyc,2162
|
|
76
|
+
testprotocols/upnp_client.py,sha256=X6LUBQ63Yfugo9qmPFwTImKrnW5rabUO_PkgOwz54SM,860
|
|
77
|
+
testprotocols/vlan_client.py,sha256=3fgjMLbBRkObODo1FD9BkJA-_ApKDQrzfc7HdAVE3Ew,578
|
|
78
|
+
testprotocols/wan_link_admin.py,sha256=w-jSBJYXAIPBjkbGt63si1sC3-3qd8AwM03zKNYnra4,1398
|
|
79
|
+
testprotocols/wifi_bss.py,sha256=d4Zo1LgULf44dRLgWcbUMFrg4YiDXxFPLMGKWr7YCs0,6368
|
|
80
|
+
testprotocols/wifi_client.py,sha256=xw5N-2t5PoRHxaWjnXYIE9W_tQWRFij1RqtiI38ZZ_o,2089
|
|
81
|
+
testprotocols/wifi_mesh.py,sha256=qWk-eSXfcfEKeCnCVF5f-7z7G8Kc306r9VCfbkx_6d4,10380
|
|
82
|
+
testprotocols/wifi_onboarding.py,sha256=oZ309o205A5g5fxvcJv-I1gEDY9Yol7_1a6TXskkJrw,4022
|
|
83
|
+
testprotocols/wifi_radio.py,sha256=gzxke_kFX5SuBnRegZzi5hDf9kIbM0IGeszO3IN8gxI,5614
|
|
84
|
+
testprotocols/wifi_rf.py,sha256=OjDGlSqkgjaWONIYxXc9l-dROkqvqgogJivTUrYt4OU,2779
|
|
85
|
+
testprotocols/wifi_stations.py,sha256=E9FEi8Q4OqC-GJNF15BlubBWVhSrT-NT0Q0WFgoWOAk,2219
|
|
86
|
+
testprotocols/wifi_transitions.py,sha256=5sFrtmoussmMYXCywmLoVcYdWoOWf_npCZIA-ltZWVk,4200
|
|
87
|
+
testprotocols/devices/__init__.py,sha256=_AYiKlz-esIIwqz9pgj_EpBxraKwhGy39jDmsmOYDKA,1531
|
|
88
|
+
testprotocols/devices/base.py,sha256=tQyKUmSsnSk_qUWlCEz3iyHklTOdLek1iTy0xYh5EZo,1799
|
|
89
|
+
testprotocols/devices/client.py,sha256=7Mh-gS-8ERqBmD0A5fNpuZ6VL5WHZkT6dPD7I6AcfDQ,5191
|
|
90
|
+
testprotocols/devices/cpe.py,sha256=csfTdnHcrlS9DRNrnsrYpEmXJ9irqYgmGZlVZKeX5_k,2486
|
|
91
|
+
testprotocols/devices/infra.py,sha256=fvNC6sh5mcS_ae19_V15IoVOe6c0PzuZui2POZqeaQw,2127
|
|
92
|
+
testprotocols/devices/sdwan.py,sha256=h_-4gGcp7OS8nlDpXRIcudfYBJ3Y6jSWhGmwsTOmxmU,4062
|
|
93
|
+
testprotocols/devices/switch.py,sha256=il9FGNYSlHfBzHt6voHK4HccPsU6rBNemUyQ5rvBiUw,4527
|
|
94
|
+
testprotocols/devices/traffic.py,sha256=n3s3STJruOJ2Z_o7ROiqrHLfEEXeXTvRebR0ftPBIOA,2027
|
|
95
|
+
testprotocols/devices/voice.py,sha256=iGwYqgPQugKgBShIKoTO7EAQg5mfDCcCCcFNd3cpVoE,2732
|
|
96
|
+
testprotocols/devices/wan.py,sha256=v0X7eVwnMfopY99EO8pA1Y_eWcY900T1h0m_d89jHIY,2272
|
|
97
|
+
testprotocols/models/__init__.py,sha256=bCgJy2XhVbf0Dwo8smKr80ywAa_kTeM_z6jvAx23NKw,6255
|
|
98
|
+
testprotocols/models/dhcp.py,sha256=Q-02veO0kRriYXETSDS0Pn20sJZox3dTm7PQB5hpsEE,685
|
|
99
|
+
testprotocols/models/firewall.py,sha256=Na-gduCszIUGE8PM2uw7QmFhF-zUxNhUMtgWiKeLBUs,6375
|
|
100
|
+
testprotocols/models/impairment.py,sha256=-jQTa2kgXf7-5y3wyTsQVF8q_J9s51apbtEdDw46adw,462
|
|
101
|
+
testprotocols/models/l2_common.py,sha256=HAbiL7jTt2DJgp6qt3yre55ROguyxKlOmz0se2HcWh0,1395
|
|
102
|
+
testprotocols/models/multicast.py,sha256=4nOhMmDcR1jcLNwJMk39xCZqM2EmSy1b-sw2JyF0zNU,597
|
|
103
|
+
testprotocols/models/networking.py,sha256=5gnTaPSATiDmBDJRLayuHn01D7TiNbfmh25FqTh0eAM,1600
|
|
104
|
+
testprotocols/models/packets.py,sha256=3t6QShpj5GpszTYn8JgkmbpPluWkjoLUrh7GmCNufhE,533
|
|
105
|
+
testprotocols/models/qoe.py,sha256=9FdMT_N9qOOXBvpHrlySKoAvtFR9z1mzmGiSUT7CUgQ,854
|
|
106
|
+
testprotocols/models/radius.py,sha256=vfXOa6bgJ776NSEfqSbtCDvAhuiPTd76g6FEp60Y38Q,1939
|
|
107
|
+
testprotocols/models/sdwan_appliance.py,sha256=dx-V1Z5FWGYPYoNiJpyGCtvWCkLwM1Tgguq6BlhfPFw,17056
|
|
108
|
+
testprotocols/models/switch.py,sha256=Ayp0WwksfErDqcWOAGSD0ex7VU6KRl1ZlP18WbC5sTY,7223
|
|
109
|
+
testprotocols/models/switch_routing.py,sha256=va-F2GUqcEAo9AmiHM_BVOHvAWfpVkylmtKnBuwVc2s,3205
|
|
110
|
+
testprotocols/models/tr069.py,sha256=DrN1tgU5JX2YebwXVe2PF_FkTXrJmv74C4t7nOhzWqM,1301
|
|
111
|
+
testprotocols/models/traffic.py,sha256=js2OPKkrUAmyXwJJ4fucZcWtW0amb1mtAn_KU--63ko,688
|
|
112
|
+
testprotocols/models/wan_edge.py,sha256=cQJ6JQg7l5boale6hTeR-Ej2-xaSLFG5KgItGv1Dga0,2667
|
|
113
|
+
testprotocols/models/wifi.py,sha256=n5-Hq1BkQ-eKvnt-rL1RPSZr00MEgwoFRK755ybaLF8,5520
|
|
114
|
+
testprotocols-0.1.0.dist-info/licenses/LICENSE,sha256=No8aJnn7SvNkXpcvHTMrPDGhtZo-usV9AitDA3bEI2s,11340
|
|
115
|
+
testprotocols-0.1.0.dist-info/licenses/NOTICE,sha256=l1ggTluhhtKw7DStHRkOpLGibFJw2CjbJXdd2W0Lbuk,404
|
|
116
|
+
testprotocols-0.1.0.dist-info/METADATA,sha256=5ruEpGBNWZE3wr_iWHzvSzA4WjD62hLoBB3p73gmdzY,1203
|
|
117
|
+
testprotocols-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
118
|
+
testprotocols-0.1.0.dist-info/top_level.txt,sha256=v_BBlzjS0Tnd8erFI6K7yel5vGoC3Snamh0V51wjs_c,14
|
|
119
|
+
testprotocols-0.1.0.dist-info/RECORD,,
|