Skip to content

Commit 2cc665a

Browse files
committedMay 8, 2024··
peer unit tests: Test frame scheduling logic
1 parent 4f25ce9 commit 2cc665a

File tree

1 file changed

+562
-0
lines changed

1 file changed

+562
-0
lines changed
 

‎tests/test_peer/test_connection.py

+562
Original file line numberDiff line numberDiff line change
@@ -1858,6 +1858,568 @@ def _on_receive_sabm(frame):
18581858
assert frames == [frame]
18591859

18601860

1861+
# RR Notification transmission, scheduling and cancellation
1862+
1863+
1864+
def test_cancel_rr_notification_notpending():
1865+
"""
1866+
Test _cancel_rr_notification does nothing if not pending.
1867+
"""
1868+
station = DummyStation(AX25Address("VK4MSL", ssid=1))
1869+
peer = TestingAX25Peer(
1870+
station=station,
1871+
address=AX25Address("VK4MSL"),
1872+
repeaters=AX25Path(),
1873+
)
1874+
1875+
assert peer._rr_notification_timeout_handle is None
1876+
1877+
peer._cancel_rr_notification()
1878+
1879+
assert peer._rr_notification_timeout_handle is None
1880+
1881+
1882+
def test_cancel_rr_notification_ispending():
1883+
"""
1884+
Test _cancel_rr_notification cancels a pending notification.
1885+
"""
1886+
station = DummyStation(AX25Address("VK4MSL", ssid=1))
1887+
peer = TestingAX25Peer(
1888+
station=station,
1889+
address=AX25Address("VK4MSL"),
1890+
repeaters=AX25Path(),
1891+
)
1892+
1893+
timeout = DummyTimeout(0, lambda: None)
1894+
peer._rr_notification_timeout_handle = timeout
1895+
1896+
peer._cancel_rr_notification()
1897+
1898+
assert peer._rr_notification_timeout_handle is None
1899+
assert timeout.cancelled is True
1900+
1901+
1902+
def test_schedule_rr_notification():
1903+
"""
1904+
Test _schedule_rr_notification schedules a notification.
1905+
"""
1906+
station = DummyStation(AX25Address("VK4MSL", ssid=1))
1907+
peer = TestingAX25Peer(
1908+
station=station,
1909+
address=AX25Address("VK4MSL"),
1910+
repeaters=AX25Path(),
1911+
)
1912+
1913+
peer._schedule_rr_notification()
1914+
1915+
assert peer._rr_notification_timeout_handle is not None
1916+
1917+
1918+
def test_send_rr_notification_connected():
1919+
"""
1920+
Test _send_rr_notification sends a notification if connected.
1921+
"""
1922+
station = DummyStation(AX25Address("VK4MSL", ssid=1))
1923+
peer = TestingAX25Peer(
1924+
station=station,
1925+
address=AX25Address("VK4MSL"),
1926+
repeaters=AX25Path(),
1927+
)
1928+
1929+
peer._init_connection(False)
1930+
1931+
count = dict(update_recv_seq=0)
1932+
1933+
def _update_recv_seq():
1934+
count["update_recv_seq"] += 1
1935+
1936+
peer._update_recv_seq = _update_recv_seq
1937+
1938+
transmitted = []
1939+
1940+
def _transmit_frame(frame):
1941+
transmitted.append(frame)
1942+
1943+
peer._transmit_frame = _transmit_frame
1944+
1945+
peer._state = AX25PeerState.CONNECTED
1946+
1947+
peer._send_rr_notification()
1948+
1949+
assert count == dict(update_recv_seq=1)
1950+
assert len(transmitted) == 1
1951+
assert isinstance(transmitted[0], AX258BitReceiveReadyFrame)
1952+
1953+
1954+
def test_send_rr_notification_disconnected():
1955+
"""
1956+
Test _send_rr_notification sends a notification if connected.
1957+
"""
1958+
station = DummyStation(AX25Address("VK4MSL", ssid=1))
1959+
peer = TestingAX25Peer(
1960+
station=station,
1961+
address=AX25Address("VK4MSL"),
1962+
repeaters=AX25Path(),
1963+
)
1964+
1965+
peer._init_connection(False)
1966+
1967+
count = dict(update_recv_seq=0)
1968+
1969+
def _update_recv_seq():
1970+
count["update_recv_seq"] += 1
1971+
1972+
peer._update_recv_seq = _update_recv_seq
1973+
1974+
transmitted = []
1975+
1976+
def _transmit_frame(frame):
1977+
transmitted.append(frame)
1978+
1979+
peer._transmit_frame = _transmit_frame
1980+
1981+
peer._state = AX25PeerState.DISCONNECTED
1982+
1983+
peer._send_rr_notification()
1984+
1985+
assert count == dict(update_recv_seq=0)
1986+
assert len(transmitted) == 0
1987+
1988+
1989+
# RNR transmission
1990+
1991+
1992+
def test_send_rnr_notification_connected():
1993+
"""
1994+
Test _send_rnr_notification sends a notification if connected.
1995+
"""
1996+
station = DummyStation(AX25Address("VK4MSL", ssid=1))
1997+
peer = TestingAX25Peer(
1998+
station=station,
1999+
address=AX25Address("VK4MSL"),
2000+
repeaters=AX25Path(),
2001+
)
2002+
2003+
peer._init_connection(False)
2004+
2005+
count = dict(update_recv_seq=0)
2006+
2007+
def _update_recv_seq():
2008+
count["update_recv_seq"] += 1
2009+
2010+
peer._update_recv_seq = _update_recv_seq
2011+
2012+
transmitted = []
2013+
2014+
def _transmit_frame(frame):
2015+
transmitted.append(frame)
2016+
2017+
peer._transmit_frame = _transmit_frame
2018+
2019+
peer._state = AX25PeerState.CONNECTED
2020+
2021+
peer._send_rnr_notification()
2022+
2023+
assert count == dict(update_recv_seq=1)
2024+
assert len(transmitted) == 1
2025+
assert isinstance(transmitted[0], AX258BitReceiveNotReadyFrame)
2026+
2027+
2028+
def test_send_rnr_notification_connected_recent():
2029+
"""
2030+
Test _send_rnr_notification skips notification if the last was recent.
2031+
"""
2032+
station = DummyStation(AX25Address("VK4MSL", ssid=1))
2033+
peer = TestingAX25Peer(
2034+
station=station,
2035+
address=AX25Address("VK4MSL"),
2036+
repeaters=AX25Path(),
2037+
)
2038+
2039+
peer._init_connection(False)
2040+
2041+
count = dict(update_recv_seq=0)
2042+
2043+
def _update_recv_seq():
2044+
count["update_recv_seq"] += 1
2045+
2046+
peer._update_recv_seq = _update_recv_seq
2047+
2048+
transmitted = []
2049+
2050+
def _transmit_frame(frame):
2051+
transmitted.append(frame)
2052+
2053+
peer._transmit_frame = _transmit_frame
2054+
2055+
peer._state = AX25PeerState.CONNECTED
2056+
peer._last_rnr_sent = peer._loop.time() - (peer._rnr_interval / 2)
2057+
2058+
peer._send_rnr_notification()
2059+
2060+
assert count == dict(update_recv_seq=0)
2061+
assert len(transmitted) == 0
2062+
2063+
2064+
def test_send_rnr_notification_disconnected():
2065+
"""
2066+
Test _send_rnr_notification sends a notification if connected.
2067+
"""
2068+
station = DummyStation(AX25Address("VK4MSL", ssid=1))
2069+
peer = TestingAX25Peer(
2070+
station=station,
2071+
address=AX25Address("VK4MSL"),
2072+
repeaters=AX25Path(),
2073+
)
2074+
2075+
peer._init_connection(False)
2076+
2077+
count = dict(update_recv_seq=0)
2078+
2079+
def _update_recv_seq():
2080+
count["update_recv_seq"] += 1
2081+
2082+
peer._update_recv_seq = _update_recv_seq
2083+
2084+
transmitted = []
2085+
2086+
def _transmit_frame(frame):
2087+
transmitted.append(frame)
2088+
2089+
peer._transmit_frame = _transmit_frame
2090+
2091+
peer._state = AX25PeerState.DISCONNECTED
2092+
2093+
peer._send_rnr_notification()
2094+
2095+
assert count == dict(update_recv_seq=0)
2096+
assert len(transmitted) == 0
2097+
2098+
2099+
# I-Frame transmission
2100+
2101+
2102+
def test_send_next_iframe_max_outstanding():
2103+
"""
2104+
Test I-frame transmission is suppressed if too many frames are pending.
2105+
"""
2106+
station = DummyStation(AX25Address("VK4MSL", ssid=1))
2107+
peer = TestingAX25Peer(
2108+
station=station,
2109+
address=AX25Address("VK4MSL"),
2110+
repeaters=AX25Path(),
2111+
)
2112+
2113+
peer._init_connection(False)
2114+
2115+
count = dict(update_send_seq=0, update_recv_seq=0)
2116+
2117+
def _update_recv_seq():
2118+
count["update_recv_seq"] += 1
2119+
2120+
peer._update_recv_seq = _update_recv_seq
2121+
2122+
def _update_send_seq():
2123+
count["update_send_seq"] += 1
2124+
2125+
peer._update_send_seq = _update_send_seq
2126+
2127+
transmitted = []
2128+
2129+
def _transmit_frame(frame):
2130+
transmitted.append(frame)
2131+
2132+
peer._transmit_frame = _transmit_frame
2133+
2134+
state_updates = []
2135+
2136+
def _update_state(**kwargs):
2137+
state_updates.append(kwargs)
2138+
2139+
peer._update_state = _update_state
2140+
2141+
peer._state = AX25PeerState.CONNECTED
2142+
peer._pending_iframes = {
2143+
0: (0xF0, b"Frame 1"),
2144+
1: (0xF0, b"Frame 2"),
2145+
2: (0xF0, b"Frame 3"),
2146+
3: (0xF0, b"Frame 4"),
2147+
4: (0xF0, b"Frame 5"),
2148+
5: (0xF0, b"Frame 6"),
2149+
6: (0xF0, b"Frame 7"),
2150+
7: (0xF0, b"Frame 8"),
2151+
}
2152+
peer._max_outstanding = 8
2153+
2154+
peer._send_next_iframe()
2155+
2156+
assert count == dict(update_send_seq=0, update_recv_seq=0)
2157+
assert state_updates == []
2158+
assert transmitted == []
2159+
2160+
2161+
def test_send_next_iframe_nothing_pending():
2162+
"""
2163+
Test I-frame transmission is suppressed no data is pending.
2164+
"""
2165+
station = DummyStation(AX25Address("VK4MSL", ssid=1))
2166+
peer = TestingAX25Peer(
2167+
station=station,
2168+
address=AX25Address("VK4MSL"),
2169+
repeaters=AX25Path(),
2170+
)
2171+
2172+
peer._init_connection(False)
2173+
2174+
count = dict(update_send_seq=0, update_recv_seq=0)
2175+
2176+
def _update_recv_seq():
2177+
count["update_recv_seq"] += 1
2178+
2179+
peer._update_recv_seq = _update_recv_seq
2180+
2181+
def _update_send_seq():
2182+
count["update_send_seq"] += 1
2183+
2184+
peer._update_send_seq = _update_send_seq
2185+
2186+
transmitted = []
2187+
2188+
def _transmit_frame(frame):
2189+
transmitted.append(frame)
2190+
2191+
peer._transmit_frame = _transmit_frame
2192+
2193+
state_updates = []
2194+
2195+
def _update_state(**kwargs):
2196+
state_updates.append(kwargs)
2197+
2198+
peer._update_state = _update_state
2199+
2200+
peer._state = AX25PeerState.CONNECTED
2201+
peer._pending_iframes = {
2202+
0: (0xF0, b"Frame 1"),
2203+
1: (0xF0, b"Frame 2"),
2204+
2: (0xF0, b"Frame 3"),
2205+
3: (0xF0, b"Frame 4"),
2206+
}
2207+
peer._max_outstanding = 8
2208+
peer._send_state = 4
2209+
2210+
peer._send_next_iframe()
2211+
2212+
assert count == dict(update_send_seq=0, update_recv_seq=0)
2213+
assert state_updates == []
2214+
assert transmitted == []
2215+
2216+
2217+
def test_send_next_iframe_create_next():
2218+
"""
2219+
Test I-frame transmission creates a new I-frame if there's data to send.
2220+
"""
2221+
station = DummyStation(AX25Address("VK4MSL", ssid=1))
2222+
peer = TestingAX25Peer(
2223+
station=station,
2224+
address=AX25Address("VK4MSL"),
2225+
repeaters=AX25Path(),
2226+
)
2227+
2228+
peer._init_connection(False)
2229+
2230+
count = dict(update_send_seq=0, update_recv_seq=0)
2231+
2232+
def _update_recv_seq():
2233+
count["update_recv_seq"] += 1
2234+
2235+
peer._update_recv_seq = _update_recv_seq
2236+
2237+
def _update_send_seq():
2238+
count["update_send_seq"] += 1
2239+
2240+
peer._update_send_seq = _update_send_seq
2241+
2242+
transmitted = []
2243+
2244+
def _transmit_frame(frame):
2245+
transmitted.append(frame)
2246+
2247+
peer._transmit_frame = _transmit_frame
2248+
2249+
state_updates = []
2250+
2251+
def _update_state(prop, **kwargs):
2252+
kwargs["prop"] = prop
2253+
state_updates.append(kwargs)
2254+
2255+
peer._update_state = _update_state
2256+
2257+
peer._state = AX25PeerState.CONNECTED
2258+
peer._pending_iframes = {
2259+
0: (0xF0, b"Frame 1"),
2260+
1: (0xF0, b"Frame 2"),
2261+
2: (0xF0, b"Frame 3"),
2262+
3: (0xF0, b"Frame 4"),
2263+
}
2264+
peer._pending_data = [
2265+
(0xF0, b"Frame 5"),
2266+
]
2267+
peer._max_outstanding = 8
2268+
peer._send_state = 4
2269+
2270+
peer._send_next_iframe()
2271+
2272+
assert peer._pending_iframes == {
2273+
0: (0xF0, b"Frame 1"),
2274+
1: (0xF0, b"Frame 2"),
2275+
2: (0xF0, b"Frame 3"),
2276+
3: (0xF0, b"Frame 4"),
2277+
4: (0xF0, b"Frame 5"),
2278+
}
2279+
assert peer._pending_data == []
2280+
assert count == dict(update_send_seq=1, update_recv_seq=1)
2281+
assert state_updates == [
2282+
dict(prop="_send_state", delta=1, comment="send next I-frame")
2283+
]
2284+
assert transmitted[1:] == []
2285+
frame = transmitted.pop(0)
2286+
assert isinstance(frame, AX258BitInformationFrame)
2287+
assert frame.payload == b"Frame 5"
2288+
2289+
2290+
def test_send_next_iframe_existing_next():
2291+
"""
2292+
Test I-frame transmission sends existing next frame.
2293+
"""
2294+
station = DummyStation(AX25Address("VK4MSL", ssid=1))
2295+
peer = TestingAX25Peer(
2296+
station=station,
2297+
address=AX25Address("VK4MSL"),
2298+
repeaters=AX25Path(),
2299+
)
2300+
2301+
peer._init_connection(False)
2302+
2303+
count = dict(update_send_seq=0, update_recv_seq=0)
2304+
2305+
def _update_recv_seq():
2306+
count["update_recv_seq"] += 1
2307+
2308+
peer._update_recv_seq = _update_recv_seq
2309+
2310+
def _update_send_seq():
2311+
count["update_send_seq"] += 1
2312+
2313+
peer._update_send_seq = _update_send_seq
2314+
2315+
transmitted = []
2316+
2317+
def _transmit_frame(frame):
2318+
transmitted.append(frame)
2319+
2320+
peer._transmit_frame = _transmit_frame
2321+
2322+
state_updates = []
2323+
2324+
def _update_state(prop, **kwargs):
2325+
kwargs["prop"] = prop
2326+
state_updates.append(kwargs)
2327+
2328+
peer._update_state = _update_state
2329+
2330+
peer._state = AX25PeerState.CONNECTED
2331+
peer._pending_iframes = {
2332+
0: (0xF0, b"Frame 1"),
2333+
1: (0xF0, b"Frame 2"),
2334+
2: (0xF0, b"Frame 3"),
2335+
3: (0xF0, b"Frame 4"),
2336+
}
2337+
peer._pending_data = [
2338+
(0xF0, b"Frame 5"),
2339+
]
2340+
peer._max_outstanding = 8
2341+
peer._send_state = 3
2342+
2343+
peer._send_next_iframe()
2344+
2345+
assert peer._pending_iframes == {
2346+
0: (0xF0, b"Frame 1"),
2347+
1: (0xF0, b"Frame 2"),
2348+
2: (0xF0, b"Frame 3"),
2349+
3: (0xF0, b"Frame 4"),
2350+
}
2351+
assert peer._pending_data == [
2352+
(0xF0, b"Frame 5"),
2353+
]
2354+
assert count == dict(update_send_seq=1, update_recv_seq=1)
2355+
assert state_updates == [
2356+
dict(prop="_send_state", delta=1, comment="send next I-frame")
2357+
]
2358+
assert transmitted[1:] == []
2359+
frame = transmitted.pop(0)
2360+
assert isinstance(frame, AX258BitInformationFrame)
2361+
assert frame.payload == b"Frame 4"
2362+
2363+
2364+
# Sequence number state updates
2365+
2366+
2367+
def test_update_send_seq():
2368+
"""
2369+
Test _update_send_seq copies V(S) to N(S).
2370+
"""
2371+
station = DummyStation(AX25Address("VK4MSL", ssid=1))
2372+
peer = TestingAX25Peer(
2373+
station=station,
2374+
address=AX25Address("VK4MSL"),
2375+
repeaters=AX25Path(),
2376+
)
2377+
2378+
state_updates = []
2379+
2380+
def _update_state(prop, **kwargs):
2381+
kwargs["prop"] = prop
2382+
state_updates.append(kwargs)
2383+
2384+
peer._update_state = _update_state
2385+
2386+
peer._send_seq = 2
2387+
peer._send_state = 6
2388+
2389+
peer._update_send_seq()
2390+
assert state_updates == [
2391+
dict(prop="_send_seq", value=6, comment="from V(S)")
2392+
]
2393+
2394+
2395+
def test_update_recv_seq():
2396+
"""
2397+
Test _update_recv_seq copies V(R) to N(R).
2398+
"""
2399+
station = DummyStation(AX25Address("VK4MSL", ssid=1))
2400+
peer = TestingAX25Peer(
2401+
station=station,
2402+
address=AX25Address("VK4MSL"),
2403+
repeaters=AX25Path(),
2404+
)
2405+
2406+
state_updates = []
2407+
2408+
def _update_state(prop, **kwargs):
2409+
kwargs["prop"] = prop
2410+
state_updates.append(kwargs)
2411+
2412+
peer._update_state = _update_state
2413+
2414+
peer._recv_state = 6
2415+
peer._recv_seq = 2
2416+
2417+
peer._update_recv_seq()
2418+
assert state_updates == [
2419+
dict(prop="_recv_seq", value=6, comment="from V(R)")
2420+
]
2421+
2422+
18612423
# SABM(E) handling
18622424

18632425

0 commit comments

Comments
 (0)
Please sign in to comment.