55
66from .helpers import FakeTCP , NoDrone
77
8+ ARM_RETRY_MAX_ATTEMPTS = 5
9+ ARM_RETRY_DELAY_SECS = 2
10+
811
912@pytest .fixture (scope = "module" , autouse = True )
1013def run_once_before_all_tests ():
@@ -51,14 +54,61 @@ def assert_drone_armed(droneStatus, armed: bool) -> None:
5154 assert bool (droneStatus .drone .master .motors_armed ()) == armed
5255
5356
57+ def arm_with_retries (droneStatus ) -> None :
58+ """Retry direct arming for transient pre-arm check failures."""
59+ for _ in range (ARM_RETRY_MAX_ATTEMPTS ):
60+ if droneStatus .drone .armed :
61+ return
62+
63+ droneStatus .drone .master .arducopter_arm ()
64+ time .sleep (ARM_RETRY_DELAY_SECS )
65+
66+ if droneStatus .drone .armed and bool (droneStatus .drone .master .motors_armed ()):
67+ return
68+
69+ raise AssertionError (
70+ f"Failed to arm after { ARM_RETRY_MAX_ATTEMPTS } attempts with "
71+ f"{ ARM_RETRY_DELAY_SECS } s delay"
72+ )
73+
74+
75+ def emit_arm_with_retries (
76+ socketio_client : SocketIOTestClient , force : bool = False
77+ ) -> dict :
78+ """Retry arm_disarm emit until success or max attempts are reached."""
79+ payload = {"arm" : True }
80+ if force :
81+ payload ["force" ] = True
82+
83+ last_response = None
84+ for _ in range (ARM_RETRY_MAX_ATTEMPTS ):
85+ socketio_client .emit ("arm_disarm" , payload )
86+ received = socketio_client .get_received ()
87+
88+ if not received :
89+ time .sleep (ARM_RETRY_DELAY_SECS )
90+ continue
91+
92+ last_response = received [0 ]["args" ][0 ]
93+ if last_response .get ("success" ):
94+ return last_response
95+
96+ time .sleep (ARM_RETRY_DELAY_SECS )
97+
98+ if last_response is not None :
99+ return last_response
100+
101+ raise AssertionError ("No response received for arm_disarm during retries" )
102+
103+
54104def test_arm_succeeds_when_disarmed (
55105 socketio_client : SocketIOTestClient , droneStatus
56106) -> None :
57107 assert_drone_armed (droneStatus , armed = False )
58108
59- socketio_client . emit ( "arm_disarm" , { "arm" : True } )
109+ response = emit_arm_with_retries ( socketio_client )
60110
61- assert socketio_client . get_received ()[ 0 ][ "args" ][ 0 ] == {
111+ assert response == {
62112 "success" : True ,
63113 "message" : "Armed successfully" ,
64114 "data" : {
@@ -73,8 +123,7 @@ def test_arm_succeeds_when_disarmed(
73123def test_arm_fails_when_already_armed (
74124 socketio_client : SocketIOTestClient , droneStatus
75125) -> None :
76- droneStatus .drone .master .arducopter_arm ()
77- time .sleep (1 )
126+ arm_with_retries (droneStatus )
78127 assert_drone_armed (droneStatus , armed = True )
79128
80129 socketio_client .emit ("arm_disarm" , {"arm" : True })
@@ -94,8 +143,7 @@ def test_arm_fails_when_already_armed(
94143def test_disarm_succeeds_when_armed (
95144 socketio_client : SocketIOTestClient , droneStatus
96145) -> None :
97- droneStatus .drone .master .arducopter_arm ()
98- time .sleep (1 )
146+ arm_with_retries (droneStatus )
99147 assert_drone_armed (droneStatus , armed = True )
100148
101149 socketio_client .emit ("arm_disarm" , {"arm" : False })
@@ -136,9 +184,9 @@ def test_force_arm_succeeds_when_disarmed(
136184) -> None :
137185 assert_drone_armed (droneStatus , armed = False )
138186
139- socketio_client . emit ( "arm_disarm" , { "arm" : True , " force" : True } )
187+ response = emit_arm_with_retries ( socketio_client , force = True )
140188
141- assert socketio_client . get_received ()[ 0 ][ "args" ][ 0 ] == {
189+ assert response == {
142190 "success" : True ,
143191 "message" : "Armed successfully" ,
144192 "data" : {
@@ -153,8 +201,7 @@ def test_force_arm_succeeds_when_disarmed(
153201def test_force_arm_fails_when_already_armed (
154202 socketio_client : SocketIOTestClient , droneStatus
155203) -> None :
156- droneStatus .drone .master .arducopter_arm ()
157- time .sleep (1 )
204+ arm_with_retries (droneStatus )
158205 assert_drone_armed (droneStatus , armed = True )
159206
160207 socketio_client .emit ("arm_disarm" , {"arm" : True , "force" : True })
@@ -174,8 +221,7 @@ def test_force_arm_fails_when_already_armed(
174221def test_force_disarm_succeeds_when_armed (
175222 socketio_client : SocketIOTestClient , droneStatus
176223) -> None :
177- droneStatus .drone .master .arducopter_arm ()
178- time .sleep (1 )
224+ arm_with_retries (droneStatus )
179225 assert_drone_armed (droneStatus , armed = True )
180226
181227 socketio_client .emit ("arm_disarm" , {"arm" : False , "force" : True })
@@ -252,8 +298,7 @@ def test_force_arm_fails_with_serial_exception(
252298def test_disarm_fails_with_serial_exception (
253299 socketio_client : SocketIOTestClient , droneStatus
254300) -> None :
255- droneStatus .drone .master .arducopter_arm ()
256- time .sleep (1 )
301+ arm_with_retries (droneStatus )
257302 assert_drone_armed (droneStatus , armed = True )
258303
259304 with FakeTCP ():
@@ -273,8 +318,7 @@ def test_disarm_fails_with_serial_exception(
273318def test_force_disarm_fails_with_serial_exception (
274319 socketio_client : SocketIOTestClient , droneStatus
275320) -> None :
276- droneStatus .drone .master .arducopter_arm ()
277- time .sleep (1 )
321+ arm_with_retries (droneStatus )
278322 assert_drone_armed (droneStatus , armed = True )
279323
280324 with FakeTCP ():
0 commit comments