Skip to content

Commit 991df7a

Browse files
committed
tests: mctpd endpoint recovery
There are several paths of interest through recovery: 1. The device is immediately responsive despite the `Recover` invocation 2. The device fails to respond prior to Treclaim 3. The device is initially unresponsive but recovers before Treclaim 4. The device has been exchanged for another Add test cases for all four. Signed-off-by: Andrew Jeffery <[email protected]>
1 parent bb01a40 commit 991df7a

File tree

2 files changed

+173
-1
lines changed

2 files changed

+173
-1
lines changed

tests/conftest.py

+3
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,9 @@ def __init__(self, iface, lladdr, ep_uuid = None, eid = 0, types = None):
197197
def __str__(self):
198198
return f"uuid {self.uuid} lladdr {self.lladdr}, eid {self.eid}"
199199

200+
def reset(self):
201+
self.eid = 0
202+
200203
class Network:
201204
def __init__(self):
202205
self.endpoints = []

tests/test_mctpd.py

+170-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,23 @@
1-
21
import pytest
2+
import trio
3+
import uuid
34

45
from mctp_test_utils import mctpd_mctp_obj, mctpd_mctp_endpoint_obj
6+
from conftest import Endpoint
7+
8+
# DBus constant symbol suffixes:
9+
#
10+
# - C: Connection
11+
# - P: Path
12+
# - I: Interface
13+
MCTPD_C = 'xyz.openbmc_project.MCTP'
14+
MCTPD_MCTP_P = '/xyz/openbmc_project/mctp'
15+
MCTPD_MCTP_I = 'au.com.CodeConstruct.MCTP'
16+
MCTPD_ENDPOINT_I = 'au.com.CodeConstruct.MCTP.Endpoint'
17+
DBUS_OBJECT_MANAGER_I = 'org.freedesktop.DBus.ObjectManager'
18+
DBUS_PROPERTIES_I = 'org.freedesktop.DBus.Properties'
19+
20+
MCTPD_TRECLAIM = 5
521

622
""" Test the SetupEndpoint dbus call
723
@@ -79,3 +95,156 @@ async def test_remove_endpoint(dbus, mctpd):
7995

8096
await ep.call_remove()
8197
assert(len(mctpd.system.neighbours) == 0)
98+
99+
async def test_recover_endpoint_present(dbus, mctpd):
100+
iface = mctpd.system.interfaces[0]
101+
dev = mctpd.network.endpoints[0]
102+
mctp = await mctpd_mctp_obj(dbus)
103+
(eid, net, path, new) = await mctp.call_setup_endpoint(iface.name, dev.lladdr)
104+
105+
ep = await dbus.get_proxy_object(MCTPD_C, path)
106+
ep_props = await ep.get_interface(DBUS_PROPERTIES_I)
107+
108+
recovered = trio.Semaphore(initial_value = 0)
109+
def ep_connectivity_changed(iface, changed, invalidated):
110+
if iface == MCTPD_ENDPOINT_I and 'Connectivity' in changed:
111+
if 'Available' == changed['Connectivity'].value:
112+
recovered.release()
113+
114+
await ep_props.on_properties_changed(ep_connectivity_changed)
115+
116+
ep_ep = await ep.get_interface(MCTPD_ENDPOINT_I)
117+
await ep_ep.call_recover()
118+
119+
with trio.move_on_after(2 * MCTPD_TRECLAIM) as expected:
120+
await recovered.acquire()
121+
122+
# Cancellation implies failure to acquire recovered, which implies failure
123+
# to transition 'Connectivity' to 'Available', which is a test failure.
124+
assert not expected.cancelled_caught
125+
126+
async def test_recover_endpoint_removed(dbus, mctpd):
127+
iface = mctpd.system.interfaces[0]
128+
dev = mctpd.network.endpoints[0]
129+
mctp = await dbus.get_proxy_object(MCTPD_C, MCTPD_MCTP_P)
130+
mctp_mctp = await mctp.get_interface(MCTPD_MCTP_I)
131+
(eid, net, path, new) = await mctp_mctp.call_setup_endpoint(iface.name, dev.lladdr)
132+
133+
ep = await dbus.get_proxy_object(MCTPD_C, path)
134+
ep_props = await ep.get_interface(DBUS_PROPERTIES_I)
135+
136+
degraded = trio.Semaphore(initial_value = 0)
137+
def ep_connectivity_changed(iface, changed, invalidated):
138+
if iface == MCTPD_ENDPOINT_I and 'Connectivity' in changed:
139+
if 'Degraded' == changed['Connectivity'].value:
140+
degraded.release()
141+
142+
await ep_props.on_properties_changed(ep_connectivity_changed)
143+
144+
mctp_objmgr = await mctp.get_interface(DBUS_OBJECT_MANAGER_I)
145+
146+
removed = trio.Semaphore(initial_value = 0)
147+
def ep_removed(ep_path, interfaces):
148+
if ep_path == path and MCTPD_ENDPOINT_I in interfaces:
149+
removed.release()
150+
151+
await mctp_objmgr.on_interfaces_removed(ep_removed)
152+
153+
del mctpd.network.endpoints[0]
154+
ep_ep = await ep.get_interface(MCTPD_ENDPOINT_I)
155+
await ep_ep.call_recover()
156+
157+
with trio.move_on_after(2 * MCTPD_TRECLAIM) as expected:
158+
await removed.acquire()
159+
await degraded.acquire()
160+
161+
assert not expected.cancelled_caught
162+
163+
async def test_recover_endpoint_reset(dbus, mctpd):
164+
iface = mctpd.system.interfaces[0]
165+
dev = mctpd.network.endpoints[0]
166+
mctp = await dbus.get_proxy_object(MCTPD_C, MCTPD_MCTP_P)
167+
mctp_mctp = await mctp.get_interface(MCTPD_MCTP_I)
168+
(eid, net, path, new) = await mctp_mctp.call_setup_endpoint(iface.name, dev.lladdr)
169+
170+
ep = await dbus.get_proxy_object(MCTPD_C, path)
171+
ep_props = await ep.get_interface(DBUS_PROPERTIES_I)
172+
173+
recovered = trio.Semaphore(initial_value = 0)
174+
def ep_connectivity_changed(iface, changed, invalidated):
175+
if iface == MCTPD_ENDPOINT_I and 'Connectivity' in changed:
176+
if 'Available' == changed['Connectivity'].value:
177+
recovered.release()
178+
179+
await ep_props.on_properties_changed(ep_connectivity_changed)
180+
181+
# Disable the endpoint device
182+
del mctpd.network.endpoints[0]
183+
184+
ep_ep = await ep.get_interface(MCTPD_ENDPOINT_I)
185+
await ep_ep.call_recover()
186+
187+
# Force the first poll to fail
188+
await trio.sleep(1)
189+
190+
# Reset the endpoint device and re-enable it
191+
dev.reset()
192+
mctpd.network.add_endpoint(dev)
193+
194+
with trio.move_on_after(2 * MCTPD_TRECLAIM) as expected:
195+
await recovered.acquire()
196+
197+
assert not expected.cancelled_caught
198+
199+
async def test_recover_endpoint_exchange(dbus, mctpd):
200+
iface = mctpd.system.interfaces[0]
201+
dev = mctpd.network.endpoints[0]
202+
mctp = await dbus.get_proxy_object(MCTPD_C, MCTPD_MCTP_P)
203+
mctp_mctp = await mctp.get_interface(MCTPD_MCTP_I)
204+
(eid, net, path, new) = await mctp_mctp.call_setup_endpoint(iface.name, dev.lladdr)
205+
206+
ep = await dbus.get_proxy_object(MCTPD_C, path)
207+
ep_props = await ep.get_interface(DBUS_PROPERTIES_I)
208+
209+
degraded = trio.Semaphore(initial_value = 0)
210+
def ep_connectivity_changed(iface, changed, invalidated):
211+
if iface == MCTPD_ENDPOINT_I and 'Connectivity' in changed:
212+
if 'Degraded' == changed['Connectivity'].value:
213+
degraded.release()
214+
215+
await ep_props.on_properties_changed(ep_connectivity_changed)
216+
217+
mctp_objmgr = await mctp.get_interface(DBUS_OBJECT_MANAGER_I)
218+
219+
removed = trio.Semaphore(initial_value = 0)
220+
def ep_removed(ep_path, interfaces):
221+
if ep_path == path and MCTPD_ENDPOINT_I in interfaces:
222+
removed.release()
223+
224+
await mctp_objmgr.on_interfaces_removed(ep_removed)
225+
226+
added = trio.Semaphore(initial_value = 0)
227+
def ep_added(ep_path, content):
228+
if MCTPD_ENDPOINT_I in content:
229+
added.release()
230+
231+
await mctp_objmgr.on_interfaces_added(ep_added)
232+
233+
# Remove the current device
234+
del mctpd.network.endpoints[0]
235+
236+
ep_ep = await ep.get_interface(MCTPD_ENDPOINT_I)
237+
await ep_ep.call_recover()
238+
239+
# Force the first poll to fail
240+
await trio.sleep(1)
241+
242+
# Add a new the endpoint device at the same physical address (different UUID)
243+
mctpd.network.add_endpoint(Endpoint(dev.iface, dev.lladdr, types = dev.types))
244+
245+
with trio.move_on_after(2 * MCTPD_TRECLAIM) as expected:
246+
await added.acquire()
247+
await removed.acquire()
248+
await degraded.acquire()
249+
250+
assert not expected.cancelled_caught

0 commit comments

Comments
 (0)