Coverage for basic_library_tests.py: 99%
899 statements
« prev ^ index » next coverage.py v7.2.7, created at 2024-04-10 15:08 +0100
« prev ^ index » next coverage.py v7.2.7, created at 2024-04-10 15:08 +0100
1#-----------------------------------------------------------------------------------
2# Library tests to check the basic function of all library object object functions
3# Calls the library functions directly rather than using the sysytem_test_harness
4#-----------------------------------------------------------------------------------
6import time
7import logging
9import system_test_harness
10from model_railway_signals.library import track_sensors
11from model_railway_signals.library import gpio_sensors
12from model_railway_signals.library import points
13from model_railway_signals.library import block_instruments
14from model_railway_signals.library import dcc_control
15from model_railway_signals.library import pi_sprog_interface
16from model_railway_signals.library import signals_common
17from model_railway_signals.library import mqtt_interface
19from model_railway_signals.editor import schematic
21#---------------------------------------------------------------------------------------------------------
22# Test Track Sensor Library objects
23#---------------------------------------------------------------------------------------------------------
25def track_sensor_callback(sensor_id, callback_type):
26 logging_string="Track Sensor Callback from Sensor "+str(sensor_id)+"-"+str(callback_type)
27 logging.info(logging_string)
29def run_track_sensor_library_tests():
30 # Test all functions - including negative tests for parameter validation
31 print("Library Tests - Track Sensor Objects")
32 canvas = schematic.canvas
33 # create_track_sensor
34 print("Library Tests - create_track_sensor - will generate 3 errors:")
35 assert len(track_sensors.track_sensors) == 0
36 track_sensors.create_track_sensor(canvas, sensor_id=100, x=100, y=100, callback=track_sensor_callback)
37 track_sensors.create_track_sensor(canvas, sensor_id=0, x=100, y=100, callback=track_sensor_callback)
38 track_sensors.create_track_sensor(canvas, sensor_id="101", x=100, y=100, callback=track_sensor_callback)
39 track_sensors.create_track_sensor(canvas, sensor_id=100, x=100, y=100, callback=track_sensor_callback)
40 assert len(track_sensors.track_sensors) == 1
41 # track_sensor_exists
42 print("Library Tests - track_sensor_exists - will generate 1 error:")
43 assert track_sensors.track_sensor_exists(100)
44 assert not track_sensors.track_sensor_exists(0)
45 assert not track_sensors.track_sensor_exists(101)
46 assert not track_sensors.track_sensor_exists("100")
47 # track_sensor_triggered (pulse the button and generate callback)
48 print("Library Tests - track_sensor_triggered - will generate 2 errors:")
49 track_sensors.track_sensor_triggered("101")
50 track_sensors.track_sensor_triggered(101)
51 print("Library Tests - track_sensor_triggered - Triggering 2 track sensor passed events:")
52 track_sensors.track_sensor_triggered(100)
53 system_test_harness.sleep(1.5)
54 # track_sensor_triggered (pulse the button and generate callback)
55 track_sensors.track_sensor_triggered(100)
56 # delete_track_sensor - reset_sensor_button function should not generate any exceptions
57 print("Library Tests - delete_track_sensor - will generate 2 errors:")
58 track_sensors.delete_track_sensor("101")
59 track_sensors.delete_track_sensor(101)
60 track_sensors.delete_track_sensor(100)
61 assert len(track_sensors.track_sensors) == 0
62 assert not track_sensors.track_sensor_exists(100)
63 print("----------------------------------------------------------------------------------------")
64 print("")
65 return()
67#---------------------------------------------------------------------------------------------------------
68# Test GPIO Sensor Library objects
69#---------------------------------------------------------------------------------------------------------
71def run_gpio_sensor_library_tests():
72 # Test all functions - including negative tests for parameter validation
73 print("Library Tests - GPIO Sensors")
74 canvas = schematic.canvas
75 # gpio_interface_enabled
76 assert gpio_sensors.gpio_interface_enabled()
77 # create_gpio_sensor - Sensor ID combinations
78 assert len(gpio_sensors.gpio_port_mappings) == 0
79 print ("GPIO Sensors - create_gpio_sensor - will generate 17 errors")
80 gpio_sensors.create_gpio_sensor(100, 4) # Success - int > 0 with valid port
81 gpio_sensors.create_gpio_sensor(101, 5) # Success - int > 0 with valid port
82 gpio_sensors.create_gpio_sensor(102, 6, signal_passed=1) # Success - int > 0 with valid port & valid callback
83 gpio_sensors.create_gpio_sensor(103, 7, signal_approach=1) # Success - int > 0 with valid port & valid callback
84 gpio_sensors.create_gpio_sensor(104, 8, sensor_passed=1) # Success - int > 0 with valid port & valid callback
85 gpio_sensors.create_gpio_sensor(105, 9, sensor_timeout=0.001) # Success - int > 0 with valid port & valid timeout
86 gpio_sensors.create_gpio_sensor(106, 10, trigger_period=0.001) # success - int > 0 with valid port & valid trigger
87 gpio_sensors.create_gpio_sensor(107, 11, trigger_period=0.005, sensor_timeout=2.0) # Success - all valid
88 assert len(gpio_sensors.gpio_port_mappings) == 8
89 # create_gpio_sensor - Invalid Sensor ID
90 gpio_sensors.create_gpio_sensor("108", 9) # Fail - Sensor ID not an int
91 gpio_sensors.create_gpio_sensor(0, 9) # Fail - Sensor ID int not > 0
92 gpio_sensors.create_gpio_sensor(100, 9) # Fail - Sensor ID duplicate
93 assert len(gpio_sensors.gpio_port_mappings) == 8
94 # create_gpio_sensor - Invalid GPIO Port
95 gpio_sensors.create_gpio_sensor(108, "5") # Fail - Port not an int
96 gpio_sensors.create_gpio_sensor(108, 14) # Fail - invalid port number
97 gpio_sensors.create_gpio_sensor(108, 4) # Fail - port already mapped
98 assert len(gpio_sensors.gpio_port_mappings) == 8
99 # create_gpio_sensor - Invalid Callback combinations
100 gpio_sensors.create_gpio_sensor(108, 6, signal_passed="1") # Fail - not an int
101 gpio_sensors.create_gpio_sensor(108, 6, signal_approach="1") # Fail - not an int
102 gpio_sensors.create_gpio_sensor(108, 6, sensor_passed="1") # Fail - not an int
103 gpio_sensors.create_gpio_sensor(108, 6, signal_passed=1, signal_approach=1, sensor_passed=1) # Fail - multiple specified
104 gpio_sensors.create_gpio_sensor(108, 6, signal_passed=1, signal_approach=1) # Fail - multiple specified
105 gpio_sensors.create_gpio_sensor(108, 6, signal_approach=1, sensor_passed=1) # Fail - multiple specified
106 gpio_sensors.create_gpio_sensor(108, 6, signal_passed=1, sensor_passed=1) # Fail - multiple specified
107 assert len(gpio_sensors.gpio_port_mappings) == 8
108 # create_gpio_sensor - Invalid Timeout and trigger period
109 gpio_sensors.create_gpio_sensor(108, 9, sensor_timeout=2) # Fail - not a float
110 gpio_sensors.create_gpio_sensor(108, 9, trigger_period=1) # Fail - not a float
111 gpio_sensors.create_gpio_sensor(108, 9, trigger_period=-1.0) # Fail - must be >= 0.0
112 gpio_sensors.create_gpio_sensor(108, 9, sensor_timeout=-1.0) # Fail - must be >= 0.0
113 assert len(gpio_sensors.gpio_port_mappings) == 8
114 # track_sensor_exists (accepts ints and strs)
115 print ("GPIO Sensors - gpio_sensor_exists - will generate 1 error")
116 assert gpio_sensors.gpio_sensor_exists(100) # True - int and exists
117 assert gpio_sensors.gpio_sensor_exists(101) # True - int and exists
118 assert gpio_sensors.gpio_sensor_exists(102) # True - int and exists
119 assert gpio_sensors.gpio_sensor_exists(103) # True - int and exists
120 assert gpio_sensors.gpio_sensor_exists(104) # True - int and exists
121 assert gpio_sensors.gpio_sensor_exists(105) # True - int and exists
122 assert gpio_sensors.gpio_sensor_exists(106) # True - int and exists
123 assert gpio_sensors.gpio_sensor_exists(107) # True - int and exists
124 assert gpio_sensors.gpio_sensor_exists("100") # True - str and exists
125 assert gpio_sensors.gpio_sensor_exists("101") # True - str and exists
126 assert gpio_sensors.gpio_sensor_exists("102") # True - str and exists
127 assert gpio_sensors.gpio_sensor_exists("103") # True - str and exists
128 assert gpio_sensors.gpio_sensor_exists("104") # True - str and exists
129 assert gpio_sensors.gpio_sensor_exists("105") # True - str and exists
130 assert gpio_sensors.gpio_sensor_exists("106") # True - str and exists
131 assert gpio_sensors.gpio_sensor_exists("107") # True - str and exists
132 assert not gpio_sensors.gpio_sensor_exists(108) # False - does not exist
133 assert not gpio_sensors.gpio_sensor_exists("108") # False - does not exist
134 assert not gpio_sensors.gpio_sensor_exists(107.0) # False (with Error) - not an int or str
135 # get_gpio_sensor_callback
136 print ("GPIO Sensors - get_gpio_sensor_callback - will generate 3 errors")
137 assert gpio_sensors.get_gpio_sensor_callback(100) == [0,0,0] # Success - ID is int
138 assert gpio_sensors.get_gpio_sensor_callback(101) == [0,0,0] # Success - ID is int
139 assert gpio_sensors.get_gpio_sensor_callback(102) == [1,0,0] # Success - ID is int
140 assert gpio_sensors.get_gpio_sensor_callback(103) == [0,1,0] # Success - ID is int
141 assert gpio_sensors.get_gpio_sensor_callback(104) == [0,0,1] # Success - ID is int
142 assert gpio_sensors.get_gpio_sensor_callback("100") == [0,0,0] # Success - ID is str
143 assert gpio_sensors.get_gpio_sensor_callback("101") == [0,0,0] # Success - ID is str
144 assert gpio_sensors.get_gpio_sensor_callback("102") == [1,0,0] # Success - ID is str
145 assert gpio_sensors.get_gpio_sensor_callback("103") == [0,1,0] # Success - ID is str
146 assert gpio_sensors.get_gpio_sensor_callback("104") == [0,0,1] # Success - ID is str
147 assert gpio_sensors.get_gpio_sensor_callback(104.0) == [0,0,0] # Error - not int or str
148 assert gpio_sensors.get_gpio_sensor_callback(108) == [0,0,0] # Error - Does not exist
149 assert gpio_sensors.get_gpio_sensor_callback("108") == [0,0,0] # Error - Does not exist
150 # remove_gpio_sensor_callbacks
151 print ("GPIO Sensors - remove_gpio_sensor_callback - will generate 3 errors")
152 gpio_sensors.remove_gpio_sensor_callback(102) # Success - int and exists
153 gpio_sensors.remove_gpio_sensor_callback("103") # success - str and exists
154 gpio_sensors.remove_gpio_sensor_callback("104") # success - str and exists
155 gpio_sensors.remove_gpio_sensor_callback(108) # Fail - Does not exist
156 gpio_sensors.remove_gpio_sensor_callback("108") # Fail - Does not exist
157 gpio_sensors.remove_gpio_sensor_callback(104.0) # Fail - not int or str
158 assert gpio_sensors.get_gpio_sensor_callback(102) == [0,0,0]
159 assert gpio_sensors.get_gpio_sensor_callback(103) == [0,0,0]
160 assert gpio_sensors.get_gpio_sensor_callback(104) == [0,0,0]
161 # add_gpio_sensor_callbacks
162 print ("GPIO Sensors - add_gpio_sensor_callback - will generate 10 errors")
163 # Set up the test condition for Sensor 105
164 gpio_sensors.add_gpio_sensor_callback(105, signal_passed=2)
165 assert gpio_sensors.get_gpio_sensor_callback(105) == [2,0,0]
166 # Tests start here
167 gpio_sensors.add_gpio_sensor_callback(102, sensor_passed=1) # Success - int and exists
168 gpio_sensors.add_gpio_sensor_callback("103", signal_passed=1) # Success - str and exists
169 gpio_sensors.add_gpio_sensor_callback("104", signal_approach=1) # Success - str and exists
170 gpio_sensors.add_gpio_sensor_callback(105) # Success - int and exists
171 gpio_sensors.add_gpio_sensor_callback(108, signal_passed=1) # Fail - Does not exist
172 gpio_sensors.add_gpio_sensor_callback("108", signal_passed=1) # Fail - Does not exist
173 gpio_sensors.add_gpio_sensor_callback(102.0, signal_passed=1) # Fail - not an int or str
174 gpio_sensors.add_gpio_sensor_callback(102, signal_passed="1") # Fail - Item not an int
175 gpio_sensors.add_gpio_sensor_callback(102, signal_approach="1") # Fail - Item not an int
176 gpio_sensors.add_gpio_sensor_callback(102, sensor_passed="1") # Fail - Item not an int
177 gpio_sensors.add_gpio_sensor_callback(102, signal_passed=1, signal_approach=1, sensor_passed=1) # Fail - multiple specified
178 gpio_sensors.add_gpio_sensor_callback(102, signal_passed=1, signal_approach=1) # Fail - multiple specified
179 gpio_sensors.add_gpio_sensor_callback(102, signal_approach=1, sensor_passed=1) # Fail - multiple specified
180 gpio_sensors.add_gpio_sensor_callback(102, signal_passed=1, sensor_passed=1) # Fail - multiple specified
181 assert gpio_sensors.get_gpio_sensor_callback(102) == [0,0,1]
182 assert gpio_sensors.get_gpio_sensor_callback(103) == [1,0,0]
183 assert gpio_sensors.get_gpio_sensor_callback(104) == [0,1,0]
184 assert gpio_sensors.get_gpio_sensor_callback(105) == [0,0,0]
185 # set_gpio_sensors_to_publish_state
186 print ("GPIO Sensors - set_gpio_sensors_to_publish_state - will generate 2 warnings and 2 errors")
187 assert len(gpio_sensors.list_of_track_sensors_to_publish) == 0
188 gpio_sensors.set_gpio_sensors_to_publish_state(105, 106) # success - int and exists
189 gpio_sensors.set_gpio_sensors_to_publish_state(200, 201) # success - int but does not yet exist
190 gpio_sensors.set_gpio_sensors_to_publish_state(105, 106) # sensors already set to publish - will generate warnings
191 gpio_sensors.set_gpio_sensors_to_publish_state("107", "108") # Fail - not an int
192 assert len(gpio_sensors.list_of_track_sensors_to_publish) == 4
193 # gpio_sensor_triggered - This is an internal function so no need to test invalid inputs
194 print ("GPIO Sensors - Sensor triggering tests - Triggering Sensors 105, 106, 107")
195 print ("GPIO Sensors - Will generate 3 Errors (signals / Track Sensors not existing)")
196 # Set up the initial state for the tests
197 gpio_sensors.add_gpio_sensor_callback(105, signal_passed=1)
198 gpio_sensors.add_gpio_sensor_callback(106, signal_approach=2)
199 gpio_sensors.add_gpio_sensor_callback(107, sensor_passed=3)
200 # Tests start here
201 gpio_sensors.gpio_sensor_triggered(9, testing=True) # Port number for GPIO Sensor 105 (timeout=0.0)
202 gpio_sensors.gpio_sensor_triggered(10, testing=True) # Port number for GPIO Sensor 106 (timeout=3.0)
203 gpio_sensors.gpio_sensor_triggered(11, testing=True) # Port number for GPIO Sensor 107 (timeout=2.0)
204 system_test_harness.sleep(1.0)
205 print ("GPIO Sensors - Re-triggering Sensor 105 (which will have time out) - Sensors 106 and 107 will be extended")
206 print ("GPIO Sensors - Will generate 1 Error (signal 1 not existing)")
207 gpio_sensors.gpio_sensor_triggered(9, testing=True) # Port number for GPIO Sensor 105 (timeout=0.0)
208 gpio_sensors.gpio_sensor_triggered(10, testing=True) # Port number for GPIO Sensor 106 (timeout=3.0)
209 gpio_sensors.gpio_sensor_triggered(11, testing=True) # Port number for GPIO Sensor 107 (timeout=2.0)
210 system_test_harness.sleep(2.5)
211 print ("GPIO Sensors - Re-triggering Sensors 105, 107 (which will have time out) - Sensors 106 will be extended")
212 print ("GPIO Sensors - Will generate 2 Errors (signal 1 / Track Sensor 3 not existing)")
213 gpio_sensors.gpio_sensor_triggered(9, testing=True) # Port number for GPIO Sensor 105 (timeout=0.0)
214 gpio_sensors.gpio_sensor_triggered(10, testing=True) # Port number for GPIO Sensor 106 (timeout=3.0)
215 gpio_sensors.gpio_sensor_triggered(11, testing=True) # Port number for GPIO Sensor 107 (timeout=2.0)
216 system_test_harness.sleep(3.5)
217 print ("GPIO Sensors - End of sensor triggering tests - all sensors should have timed out")
218 # subscribe_to_remote_gpio_sensor
219 print ("GPIO Sensors - subscribe_to_remote_gpio_sensor - Will generate 1 warning and 10 Errors")
220 assert len(gpio_sensors.gpio_port_mappings) == 8
221 gpio_sensors.subscribe_to_remote_gpio_sensor("box1-200") # Success - valid remote ID
222 gpio_sensors.subscribe_to_remote_gpio_sensor("box1-201", signal_passed=1) # Success
223 gpio_sensors.subscribe_to_remote_gpio_sensor("box1-202", signal_approach=1) # Success
224 gpio_sensors.subscribe_to_remote_gpio_sensor("box1-203", sensor_passed=1) # Success
225 gpio_sensors.subscribe_to_remote_gpio_sensor("box1-200") # Warning - This is a duplicate
226 gpio_sensors.subscribe_to_remote_gpio_sensor(120) # Fail - not a string
227 gpio_sensors.subscribe_to_remote_gpio_sensor("box1") # Fail - not valid remote ID
228 gpio_sensors.subscribe_to_remote_gpio_sensor("200") # Fail - not valid remote ID
229 gpio_sensors.subscribe_to_remote_gpio_sensor("box1-201", signal_passed="1") # Fail - not an int
230 gpio_sensors.subscribe_to_remote_gpio_sensor("box1-201", signal_approach="1") # Fail - not an int
231 gpio_sensors.subscribe_to_remote_gpio_sensor("box1-201", sensor_passed="1") # Fail - not an int
232 gpio_sensors.subscribe_to_remote_gpio_sensor("box1-201", signal_passed=1, signal_approach=1, sensor_passed=1) # Fail - multiple specified
233 gpio_sensors.subscribe_to_remote_gpio_sensor("box1-201", signal_passed=1, signal_approach=1) # Fail - multiple specified
234 gpio_sensors.subscribe_to_remote_gpio_sensor("box1-201", signal_approach=1, sensor_passed=1) # Fail - multiple specified
235 gpio_sensors.subscribe_to_remote_gpio_sensor("box1-101", signal_passed=1, sensor_passed=1) # Fail - multiple specified
236 assert gpio_sensors.gpio_sensor_exists("box1-200")
237 assert gpio_sensors.gpio_sensor_exists("box1-201")
238 assert gpio_sensors.gpio_sensor_exists("box1-202")
239 assert gpio_sensors.gpio_sensor_exists("box1-203")
240 assert len(gpio_sensors.gpio_port_mappings) == 12
241 # Check the callbacks have been setup correctly
242 assert gpio_sensors.get_gpio_sensor_callback("box1-200") == [0,0,0]
243 assert gpio_sensors.get_gpio_sensor_callback("box1-201") == [1,0,0]
244 assert gpio_sensors.get_gpio_sensor_callback("box1-202") == [0,1,0]
245 assert gpio_sensors.get_gpio_sensor_callback("box1-203") == [0,0,1]
246 # Test the triggering of remote sensors:
247 print ("GPIO Sensors - handle_mqtt_gpio_sensor_triggered_event - will generate 3 errors and 2 warnings")
248 gpio_sensors.handle_mqtt_gpio_sensor_triggered_event({"sourceidentifier": "box1-200"})
249 gpio_sensors.handle_mqtt_gpio_sensor_triggered_event({"sourceidentifier": "box1-201"})
250 gpio_sensors.handle_mqtt_gpio_sensor_triggered_event({"sourceidentifier": "box1-202"})
251 gpio_sensors.handle_mqtt_gpio_sensor_triggered_event({"sourceidentifier": "box1-203"})
252 gpio_sensors.handle_mqtt_gpio_sensor_triggered_event({"wrongkey": "box1-200"}) # Fail - spurious message
253 gpio_sensors.handle_mqtt_gpio_sensor_triggered_event({"sourceidentifier": "box1-150"}) # Fail - not subscribed
254 system_test_harness.sleep (1.0)
255 # reset_mqtt_configuration (all remote sensors will be deleted)
256 print ("GPIO Sensors - reset_mqtt_configuration")
257 gpio_sensors.reset_mqtt_configuration()
258 assert len(gpio_sensors.gpio_port_mappings) == 8
259 assert not gpio_sensors.gpio_sensor_exists("box1-200")
260 assert not gpio_sensors.gpio_sensor_exists("box1-201")
261 assert not gpio_sensors.gpio_sensor_exists("box1-202")
262 assert not gpio_sensors.gpio_sensor_exists("box1-203")
263 assert gpio_sensors.gpio_sensor_exists(100)
264 assert gpio_sensors.gpio_sensor_exists(101)
265 assert gpio_sensors.gpio_sensor_exists(102)
266 assert gpio_sensors.gpio_sensor_exists(103)
267 assert gpio_sensors.gpio_sensor_exists(104)
268 assert gpio_sensors.gpio_sensor_exists(105)
269 assert gpio_sensors.gpio_sensor_exists(106)
270 assert gpio_sensors.gpio_sensor_exists(107)
271 print ("GPIO Sensors - delete_all_local_gpio_sensors")
272 # Subscribe to remote sensors to test delete of local sensors
273 gpio_sensors.subscribe_to_remote_gpio_sensor("box1-200")
274 gpio_sensors.subscribe_to_remote_gpio_sensor("box1-201")
275 assert len(gpio_sensors.gpio_port_mappings) == 10
276 # delete_all_local_gpio_sensors
277 gpio_sensors.delete_all_local_gpio_sensors()
278 assert not gpio_sensors.gpio_sensor_exists(100)
279 assert not gpio_sensors.gpio_sensor_exists(101)
280 assert not gpio_sensors.gpio_sensor_exists(102)
281 assert not gpio_sensors.gpio_sensor_exists(103)
282 assert not gpio_sensors.gpio_sensor_exists(104)
283 assert not gpio_sensors.gpio_sensor_exists(105)
284 assert not gpio_sensors.gpio_sensor_exists(106)
285 assert not gpio_sensors.gpio_sensor_exists(107)
286 assert gpio_sensors.gpio_sensor_exists("box1-200")
287 assert gpio_sensors.gpio_sensor_exists("box1-201")
288 assert len(gpio_sensors.gpio_port_mappings) == 2
289 gpio_sensors.reset_mqtt_configuration()
290 assert len(gpio_sensors.gpio_port_mappings) == 0
291 # gpio_shutdown
292 print ("GPIO Sensors - gpio_shutdown immediately after a trigger event")
293 gpio_sensors.create_gpio_sensor(100, 4)
294 gpio_sensors.gpio_sensor_triggered(4, testing=True)
295 gpio_sensors.gpio_shutdown()
296 gpio_sensors.gpio_sensor_triggered(4, testing=True)
297 print("----------------------------------------------------------------------------------------")
298 print("")
299 return()
301#---------------------------------------------------------------------------------------------------------
302# Test Point Library objects
303#---------------------------------------------------------------------------------------------------------
305def point_callback(point_id, callback_type):
306 logging_string="Point Callback from Point "+str(point_id)+"-"+str(callback_type)
307 logging.info(logging_string)
309def run_point_library_tests():
310 # Test all functions - including negative tests for parameter validation
311 print("Library Tests - Point Objects")
312 canvas = schematic.canvas
313 # create_point
314 assert len(points.points) == 0
315 # Point ID and point_type combinations
316 print("Library Tests - create_point - will generate 7 errors:")
317 points.create_point(canvas, 100, points.point_type.RH, 100, 100, point_callback) # Valid
318 points.create_point(canvas, 101, points.point_type.LH, 200, 100, point_callback, auto=True) # Valid
319 points.create_point(canvas, 102, points.point_type.RH, 300, 100, point_callback, also_switch=101) # Valid
320 points.create_point(canvas, 103, points.point_type.LH, 400, 100, point_callback, auto=True) # Valid
321 points.create_point(canvas, 104, points.point_type.LH, 500, 100, point_callback, fpl=True) # Valid
322 points.create_point(canvas, 0, points.point_type.RH, 100, 100, point_callback)
323 points.create_point(canvas, "100", points.point_type.RH,100, 100, point_callback)
324 points.create_point(canvas, 100, points.point_type.RH, 100, 100, point_callback)
325 points.create_point(canvas, 105, "random-type", 100, 100, point_callback)
326 # Alsoswitch combinations
327 points.create_point(canvas, 106, points.point_type.LH, 100, 100, point_callback, also_switch="100")
328 points.create_point(canvas, 107, points.point_type.LH, 100, 100, point_callback, also_switch=107)
329 # Automatic and FPL combinations
330 points.create_point(canvas, 108, points.point_type.LH, 100, 100, point_callback, auto=True, fpl=True)
331 assert len(points.points) == 5
332 # point_exists
333 print("Library Tests - point_exists - will generate 1 error:")
334 assert points.point_exists(100)
335 assert points.point_exists(101)
336 assert points.point_exists(102)
337 assert points.point_exists(103)
338 assert points.point_exists(104)
339 assert not points.point_exists(105)
340 assert not points.point_exists(106)
341 assert not points.point_exists(107)
342 assert not points.point_exists(108)
343 assert not points.point_exists("100") # Invalid
344 # toggle_point and point/fpl state
345 print("Library Tests - point_switched - will generate 2 errors:")
346 assert not points.point_switched(100)
347 assert not points.point_switched(101)
348 assert not points.point_switched(102)
349 assert not points.point_switched(103)
350 assert not points.point_switched(104)
351 assert not points.point_switched("100") # Invalid
352 assert not points.point_switched(105) # Does not exist
353 print("Library Tests - fpl_active - will generate 2 errors:")
354 assert points.fpl_active(100)
355 assert points.fpl_active(101)
356 assert points.fpl_active(102)
357 assert points.fpl_active(103)
358 assert points.fpl_active(104)
359 assert not points.fpl_active("100") # Invalid
360 assert not points.fpl_active(105) # Does not exist
361 print("Library Tests - toggle_point to 'switched' - will generate 3 errors and 1 warning:")
362 points.toggle_point(100)
363 points.toggle_point(102) # 102 will autoswitch 101
364 points.toggle_point(104) # 104 has FPL so will generate warning
365 points.toggle_point(103) # 103 is auto so will generate error
366 points.toggle_point("100") # Invalid
367 points.toggle_point(105) # Does not exist
368 print("Library Tests - toggle_point to 'normal' - will generate 1 error and 1 warning:")
369 assert points.point_switched(100)
370 assert points.point_switched(101)
371 assert points.point_switched(102)
372 assert not points.point_switched(103)
373 assert points.point_switched(104)
374 points.lock_point(104)
375 points.toggle_point(100)
376 points.toggle_point(102) # 102 will autoswitch 101
377 points.toggle_point(103) # 103 is auto so will generate error
378 points.toggle_point(104) # 104 has FPL so will generate warning
379 points.unlock_point(104)
380 assert not points.point_switched(100)
381 assert not points.point_switched(101)
382 assert not points.point_switched(102)
383 assert not points.point_switched(103)
384 assert not points.point_switched(104)
385 # FPL specific tests
386 print("Library Tests - toggle_fpl - will generate 3 errors and 2 warnings:")
387 points.toggle_fpl("100") # Invalid
388 points.toggle_fpl(100) # No FPL
389 points.toggle_fpl(105) # Does not exist
390 assert points.fpl_active(104)
391 points.toggle_fpl(104) # Has FPL - toggle off FPL
392 assert not points.fpl_active(104)
393 points.toggle_point(104) # Has FPL - switch point
394 assert points.point_switched(104)
395 points.toggle_point(104) # Has FPL - switch pointback to 'normal'
396 assert not points.point_switched(104)
397 points.lock_point(104) # Will activate FPL with a warning
398 points.toggle_fpl(104) # Toggle FPL to OFF with point locked - will generate warning
399 assert not points.fpl_active(104)
400 points.unlock_point(104)
401 # Test the button callback functions
402 print("Library Tests - Point button callback functions:")
403 assert not points.fpl_active(104)
404 points.change_button_event(104) # Has FPL - switch point
405 assert points.point_switched(104)
406 points.change_button_event(104) # Has FPL - switch pointback to 'normal'
407 assert not points.point_switched(104)
408 points.fpl_button_event(104) # Has FPL - toggle on FPL
409 assert points.fpl_active(104)
410 # Note we leave the FPL off for the next tests to generate warnings
411 points.fpl_button_event(104) # Has FPL - toggle off FPL
412 # Lock Point
413 print("Library Tests - lock_point - will generate 2 errors and 1 warning:")
414 assert points.points[str(100)]['locked']==False
415 assert points.points[str(104)]['locked']==False
416 points.lock_point("100") # Invalid
417 points.lock_point(105) # Does not exist
418 points.lock_point(100)
419 points.lock_point(104)
420 points.lock_point(104)
421 assert points.points[str(100)]['locked']==True
422 assert points.points[str(104)]['locked']==True
423 print("Library Tests - unlock_point - will generate 2 errors:")
424 points.unlock_point("100") # Invalid
425 points.unlock_point(105) # Does not exist
426 points.unlock_point(100)
427 points.unlock_point(104)
428 points.unlock_point(104)
429 assert points.points[str(100)]['locked']==False
430 assert points.points[str(104)]['locked']==False
431 # Update autoswitch
432 print("Library Tests - update_autoswitch - will generate 4 errors:")
433 points.update_autoswitch("100", 103)
434 points.update_autoswitch(105, 103) # Point 105 does not exist
435 points.update_autoswitch(102, "109")
436 points.update_autoswitch(102, 105)
437 points.toggle_point(102) # 102 was autoswitching 101
438 assert points.point_switched(102)
439 assert not points.point_switched(103)
440 points.update_autoswitch(102, 103)
441 assert points.point_switched(102)
442 assert points.point_switched(103)
443 points.toggle_point(102)
444 assert not points.point_switched(102)
445 assert not points.point_switched(103)
446 print("Library Tests - update_autoswitch to a non-auto point - will generate 2 errors:")
447 points.update_autoswitch(102, 100)
448 points.toggle_point(102)
449 assert points.point_switched(102)
450 assert not points.point_switched(100)
451 # delete point
452 print("Library Tests - delete_point - will generate 2 errors:")
453 assert len(points.points) == 5
454 points.delete_point("100")
455 points.delete_point(105) # Point 105 does not exist
456 points.delete_point(100)
457 points.delete_point(101)
458 points.delete_point(103)
459 points.delete_point(104)
460 assert not points.point_exists(100)
461 assert not points.point_exists(101)
462 assert not points.point_exists(103)
463 assert not points.point_exists(104)
464 assert len(points.points) == 1
465 print("Library Tests - autoswitch a deleted point - will generate 1 error:")
466 points.toggle_point(102)
467 points.delete_point(102)
468 assert not points.point_exists(102)
469 assert len(points.points) == 0
470 print("Library Tests - create autoswitched point - will generate 1 warning:")
471 points.create_point(canvas, 100, points.point_type.LH, 100, 100, point_callback, also_switch=101) # Valid
472 points.toggle_point_state(100)
473 points.create_point(canvas, 101, points.point_type.LH, 200, 100, point_callback, auto=True) # Valid
474 assert len(points.points) == 2
475 assert points.point_switched(100)
476 assert points.point_switched(101)
477 points.create_point(canvas, 102, points.point_type.LH, 300, 100, point_callback, also_switch=101) # Valid
478 assert points.point_switched(100)
479 assert not points.point_switched(101)
480 assert not points.point_switched(101)
481 print("Library Tests - clean up by deleting all points")
482 points.delete_point(100)
483 points.delete_point(101)
484 points.delete_point(102)
485 assert len(points.points) == 0
486 print("----------------------------------------------------------------------------------------")
487 print("")
488 return()
490#---------------------------------------------------------------------------------------------------------
491# Test Block Instrument Library objects
492#---------------------------------------------------------------------------------------------------------
494def instrument_callback(instrument_id, callback_type):
495 logging_string="Instrument Callback from Instrument "+str(instrument_id)+"-"+str(callback_type)
496 logging.info(logging_string)
498def run_instrument_library_tests():
499 # Test all functions - including negative tests for parameter validation
500 print("Library Tests - Instrument Objects")
501 canvas = schematic.canvas
502 # create_instrument
503 print("Library Tests - create_instrument - 6 Errors and 4 warnings will be generated")
504 assert len(block_instruments.instruments) == 0
505 # Sunny day tests
506 block_instruments.create_instrument(canvas, 1, block_instruments.instrument_type.single_line, 100, 100, instrument_callback, linked_to="2")
507 block_instruments.create_instrument(canvas, 2, block_instruments.instrument_type.single_line, 200, 100, instrument_callback, linked_to="1")
508 block_instruments.create_instrument(canvas, 3, block_instruments.instrument_type.double_line, 300, 100, instrument_callback, linked_to="4")
509 block_instruments.create_instrument(canvas, 4, block_instruments.instrument_type.double_line, 400, 100, instrument_callback, linked_to="3")
510 block_instruments.create_instrument(canvas, 5, block_instruments.instrument_type.double_line, 500, 100, instrument_callback, linked_to="box1-5")
511 block_instruments.create_instrument(canvas, 6, block_instruments.instrument_type.single_line, 600, 100, instrument_callback, linked_to="9")
512 # Raise a warning because Instrument 6 is already linked to instrument 9
513 block_instruments.create_instrument(canvas, 7, block_instruments.instrument_type.single_line, 700, 100, instrument_callback, linked_to="9") # warning
514 # Raise a warning because Instrument 5 is linked back to a completely different instrument (instrument "box1-5")
515 block_instruments.create_instrument(canvas, 8, block_instruments.instrument_type.single_line, 800, 100, instrument_callback, linked_to="5") # Warning
516 # Raise a warning because we are linking to instrument 8 but Instruments 6 and 7 are already linked to back to 'our' instrument
517 block_instruments.create_instrument(canvas, 9, block_instruments.instrument_type.single_line, 900, 100, instrument_callback, linked_to="10") # Warning
518 # Rainy day tests:
519 block_instruments.create_instrument(canvas, 0, block_instruments.instrument_type.single_line, 100, 100, instrument_callback, linked_to="10") # Fail (int <1)
520 block_instruments.create_instrument(canvas, 4, block_instruments.instrument_type.single_line, 100, 100, instrument_callback, linked_to="10") # Fail (Exists)
521 block_instruments.create_instrument(canvas, "10", block_instruments.instrument_type.single_line, 100, 100, instrument_callback, linked_to="10") # Fail (str)
522 block_instruments.create_instrument(canvas, 10, "random_type", 100, 100, instrument_callback, linked_to="2") # Fail
523 block_instruments.create_instrument(canvas, 11, block_instruments.instrument_type.single_line, 100, 100, instrument_callback, linked_to=10) # Fail
524 block_instruments.create_instrument(canvas, 12, block_instruments.instrument_type.single_line, 100, 100, instrument_callback, linked_to="box1") # Fail
525 assert len(block_instruments.instruments) == 9
526 print("Library Tests - instrument_exists - 1 Error will be generated")
527 assert block_instruments.instrument_exists("1")
528 assert block_instruments.instrument_exists("2")
529 assert block_instruments.instrument_exists("3")
530 assert block_instruments.instrument_exists("4")
531 assert block_instruments.instrument_exists(5)
532 assert block_instruments.instrument_exists(6)
533 assert block_instruments.instrument_exists(7)
534 assert block_instruments.instrument_exists(8)
535 assert block_instruments.instrument_exists(9)
536 assert not block_instruments.instrument_exists("10")
537 assert not block_instruments.instrument_exists(10)
538 assert not block_instruments.instrument_exists(10.1)
539 print("Library Tests - block_section_ahead_clear - Part 1 - 2 Errors will be generated")
540 assert not block_instruments.block_section_ahead_clear(1)
541 assert not block_instruments.block_section_ahead_clear(2)
542 assert not block_instruments.block_section_ahead_clear(3)
543 assert not block_instruments.block_section_ahead_clear(4)
544 assert not block_instruments.block_section_ahead_clear("5")
545 assert not block_instruments.block_section_ahead_clear(10)
546 print("Library Tests - block_section_ahead_clear - Part 2 - Testing instrument states (no errors or warnings)")
547 block_instruments.clear_button_event(1)
548 block_instruments.clear_button_event(3)
549 block_instruments.clear_button_event(3)
550 assert block_instruments.block_section_ahead_clear(2)
551 assert block_instruments.block_section_ahead_clear(4)
552 assert not block_instruments.block_section_ahead_clear(1)
553 assert not block_instruments.block_section_ahead_clear(3)
554 block_instruments.occup_button_event(1)
555 block_instruments.occup_button_event(3)
556 block_instruments.occup_button_event(3)
557 assert not block_instruments.block_section_ahead_clear(1)
558 assert not block_instruments.block_section_ahead_clear(2)
559 assert not block_instruments.block_section_ahead_clear(3)
560 assert not block_instruments.block_section_ahead_clear(4)
561 block_instruments.blocked_button_event(1)
562 block_instruments.blocked_button_event(3)
563 block_instruments.blocked_button_event(3)
564 assert not block_instruments.block_section_ahead_clear(1)
565 assert not block_instruments.block_section_ahead_clear(2)
566 assert not block_instruments.block_section_ahead_clear(3)
567 assert not block_instruments.block_section_ahead_clear(4)
568 block_instruments.clear_button_event(2)
569 block_instruments.clear_button_event(4)
570 assert block_instruments.block_section_ahead_clear(1)
571 assert block_instruments.block_section_ahead_clear(3)
572 assert not block_instruments.block_section_ahead_clear(2)
573 assert not block_instruments.block_section_ahead_clear(4)
574 block_instruments.blocked_button_event(2)
575 block_instruments.blocked_button_event(4)
576 print("Library Tests - update_linked_instrument - 5 Errors and 5 warnings will be generated")
577 # Clear down the spurious linkings
578 block_instruments.update_linked_instrument(5,"")
579 block_instruments.update_linked_instrument(6,"")
580 block_instruments.update_linked_instrument(7,"")
581 block_instruments.update_linked_instrument(8,"")
582 block_instruments.update_linked_instrument(9,"")
583 # Make the new linkings
584 block_instruments.update_linked_instrument(5,"4")
585 block_instruments.update_linked_instrument(4,"5")
586 block_instruments.update_linked_instrument(1,"6")
587 block_instruments.update_linked_instrument(6,"1")
588 block_instruments.update_linked_instrument(4,"4") # Fail - same ID
589 block_instruments.update_linked_instrument(10,"7") # Fail -Inst ID does not exist
590 block_instruments.update_linked_instrument("1","2") # Fail - Inst ID not an int
591 block_instruments.update_linked_instrument(1,2) # Fail - Linked ID not a str
592 block_instruments.update_linked_instrument(1,"box1") # Fail - linked ID npot valid remote ID
593 print("Library Tests - set_instruments_to_publish_state - 3 Errors and 4 warnings will be generated")
594 assert len(block_instruments.list_of_instruments_to_publish) == 0
595 block_instruments.set_instruments_to_publish_state(1,2,5,20)
596 block_instruments.set_instruments_to_publish_state(1,2,5,20) # Already set to publish - 4 warnings
597 block_instruments.set_instruments_to_publish_state("1,","2") # Not integers - 2 Errors
598 block_instruments.set_instruments_to_publish_state(0) # Integer but < 1 - 1 Error
599 assert len(block_instruments.list_of_instruments_to_publish) == 4
600 print("Library Tests - set_instruments_to_publish_state - Exercise Publishing of Events code")
601 # Clear down the existing linked instruments first
602 block_instruments.update_linked_instrument(4,"")
603 block_instruments.update_linked_instrument(1,"")
604 block_instruments.update_linked_instrument(5,"Box2-150")
605 block_instruments.update_linked_instrument(6,"Box2-160")
606 block_instruments.clear_button_event(5)
607 block_instruments.blocked_button_event(5)
608 block_instruments.telegraph_key_button(5)
609 block_instruments.clear_button_event(6)
610 block_instruments.blocked_button_event(6)
611 block_instruments.telegraph_key_button(6)
612 print("Library Tests - subscribe_to_remote_instrument - 3 Errors and 1 Warning will be generated")
613 block_instruments.subscribe_to_remote_instrument("box2-200")
614 block_instruments.subscribe_to_remote_instrument("box2-200") # Warning - This is a duplicate
615 block_instruments.subscribe_to_remote_instrument(120) # Fail - not a string
616 block_instruments.subscribe_to_remote_instrument("box2") # Fail - not valid remote ID
617 block_instruments.subscribe_to_remote_instrument("200") # Fail - not valid remote ID
618 assert len(block_instruments.instruments) == 10
619 assert block_instruments.instrument_exists("box2-200")
620 print("Library Tests - handle_mqtt_instrument_updated_event - 5 Warnings will be generated")
621 assert not block_instruments.block_section_ahead_clear(1)
622 block_instruments.handle_mqtt_instrument_updated_event({"sourceidentifier": "box2-200", "sectionstate": True, "instrumentid":"box1-1" })
623 assert block_instruments.block_section_ahead_clear(1)
624 block_instruments.handle_mqtt_instrument_updated_event({"sourceidentifier": "box2-200", "sectionstate": False, "instrumentid":"box1-1" })
625 assert not block_instruments.block_section_ahead_clear(1)
626 block_instruments.handle_mqtt_instrument_updated_event({"sourceidentifier": "box2-200", "sectionstate": None, "instrumentid":"box1-1" })
627 assert not block_instruments.block_section_ahead_clear(1)
628 block_instruments.handle_mqtt_instrument_updated_event({"sourceidentifier":"box2-200","sectionstate":None,"instrumentid":"random" }) # Invalid ID
629 block_instruments.handle_mqtt_instrument_updated_event({"sourceidentifier":"box2-150","sectionstate":False,"instrumentid":"box1-1"}) # Not subscribed
630 block_instruments.handle_mqtt_instrument_updated_event({"sourceidentifier":"box2-150","instrumentid":"box1-1"}) # Fail - spurious message
631 block_instruments.handle_mqtt_instrument_updated_event({"sectionstate": False, "instrumentid":"box1-1"}) # Fail - spurious message
632 block_instruments.handle_mqtt_instrument_updated_event({"sourceidentifier":"box2-150","sectionstate": False}) # Fail - spurious message
633 print("Library Tests - handle_mqtt_ring_section_bell_event - 4 Warnings will be generated")
634 block_instruments.handle_mqtt_ring_section_bell_event({"sourceidentifier": "box2-200", "instrumentid":"box1-1" })
635 block_instruments.handle_mqtt_ring_section_bell_event({"sourceidentifier": "box2-200", "instrumentid":"box1-1" })
636 block_instruments.handle_mqtt_ring_section_bell_event({"sourceidentifier": "box2-200", "instrumentid":"box1-1" })
637 block_instruments.handle_mqtt_ring_section_bell_event({"sourceidentifier": "box2-200", "instrumentid":"random" }) # Invalid ID
638 block_instruments.handle_mqtt_ring_section_bell_event({"sourceidentifier": "box2-150", "sectionstate": False}) # Not subscribed
639 block_instruments.handle_mqtt_ring_section_bell_event({"instrumentid": "box2-1"}) # Fail - spurious message
640 block_instruments.handle_mqtt_ring_section_bell_event({"sourceidentifier": "box2-200"}) # Fail - spurious message
641 print("Library Tests - reset_mqtt_configuration (all subscribed instruments will be deleted)")
642 block_instruments.reset_mqtt_configuration()
643 assert len(block_instruments.list_of_instruments_to_publish) == 0
644 assert len(block_instruments.instruments) == 9
645 assert not block_instruments.instrument_exists("box1-200")
646 print("Library Tests - delete_instrument - 2 Errors will be generated")
647 block_instruments.delete_instrument(1)
648 block_instruments.delete_instrument(2)
649 block_instruments.delete_instrument(3)
650 block_instruments.delete_instrument(4)
651 block_instruments.delete_instrument(5)
652 block_instruments.delete_instrument(6)
653 block_instruments.delete_instrument(7)
654 block_instruments.delete_instrument(8)
655 block_instruments.delete_instrument(9)
656 assert len(block_instruments.instruments) == 0
657 assert not block_instruments.instrument_exists(1)
658 assert not block_instruments.instrument_exists(2)
659 assert not block_instruments.instrument_exists(3)
660 assert not block_instruments.instrument_exists(4)
661 assert not block_instruments.instrument_exists(5)
662 assert not block_instruments.instrument_exists(6)
663 assert not block_instruments.instrument_exists(7)
664 assert not block_instruments.instrument_exists(8)
665 assert not block_instruments.instrument_exists(9)
666 block_instruments.delete_instrument(10) # Fail
667 block_instruments.delete_instrument("10") # Fail
668 print("----------------------------------------------------------------------------------------")
669 print("")
670 return()
672#---------------------------------------------------------------------------------------------------------
673# Test Pi-Sprog interface - Requires Harman SC1 to be connected for CV read/write tests (set to address 1)
674#---------------------------------------------------------------------------------------------------------
676def run_pi_sprog_interface_tests(baud_rate):
677 # Test all functions - including negative tests for parameter validation
678 print("Library Tests - Pi Sprog Interface Tests")
679 print("Library Tests - sprog_connect - 3 Errors will be generated")
680 assert not pi_sprog_interface.sprog_connect (0, 115200) # Fail - Port name not a str
681 assert not pi_sprog_interface.sprog_connect ("/dev/serial0", "115200") # Fail - Baud Rate not an int
682 assert not pi_sprog_interface.sprog_connect ("/dev/serial0", baud_rate, "True") # Fail - Debug mode not a bool
683 assert pi_sprog_interface.sprog_connect ("/dev/serial0", baud_rate, False) # Success
684 print("Library Tests - sprog_disconnect and reconnect (no errors or warnings)")
685 assert pi_sprog_interface.sprog_disconnect()
686 assert pi_sprog_interface.sprog_connect ("/dev/serial0", baud_rate, True)
687 print("Library Tests - dcc_power_on and dcc_power_off (no errors or warnings)")
688 assert pi_sprog_interface.request_dcc_power_on()
689 assert pi_sprog_interface.request_dcc_power_off()
690 print("Library Tests - service_mode_read_cv - 2 Errors should be generated")
691 assert pi_sprog_interface.request_dcc_power_on()
692 assert pi_sprog_interface.service_mode_read_cv("1") is None # Fail
693 assert pi_sprog_interface.service_mode_read_cv(1024) is None # Fail
694 cv1_value = pi_sprog_interface.service_mode_read_cv(1) # Success
695 cv9_value = pi_sprog_interface.service_mode_read_cv(9) # Success
696 assert cv1_value is not None
697 assert cv9_value is not None
698 print("Library Tests - service_mode_write_cv - 4 Errors should be generated")
699 assert not pi_sprog_interface.service_mode_write_cv("1", 123) # Fail - CV not an int
700 assert not pi_sprog_interface.service_mode_write_cv(1024, 123) # Fail - CV out of range
701 assert not pi_sprog_interface.service_mode_write_cv(1, "123") # Fail - Value not an int
702 assert not pi_sprog_interface.service_mode_write_cv(1, 256) # Fail - Value out of range
703 print("Library Tests - service_mode_write_cv - Set new values for CV1 and CV9 (no errors or warnings)")
704 assert pi_sprog_interface.service_mode_write_cv(1, 123) # Success
705 assert pi_sprog_interface.service_mode_write_cv(9, 255) # Success
706 print("Library Tests - service_mode_write_cv - Read back the values to confirm (no errors or warnings)")
707 assert pi_sprog_interface.service_mode_read_cv(1) == 123 # Success
708 assert pi_sprog_interface.service_mode_read_cv(9) == 255 # Success
709 print("Library Tests - service_mode_write_cv - Set the values back to what they were (no errors or warnings)")
710 assert pi_sprog_interface.service_mode_write_cv(1, cv1_value) # Success
711 assert pi_sprog_interface.service_mode_write_cv(9, cv9_value) # Success
712 print("Library Tests - service_mode_write_cv - Confirm the values have been set back (no errors or warnings)")
713 assert pi_sprog_interface.service_mode_read_cv(1) == cv1_value # Success
714 assert pi_sprog_interface.service_mode_read_cv(9) == cv9_value # Success
715 assert pi_sprog_interface.request_dcc_power_off()
716 print("Library Tests - send_accessory_short_event - 3 Errors should be generated")
717 assert pi_sprog_interface.request_dcc_power_on()
718 pi_sprog_interface.send_accessory_short_event("1", True) # Fail - address not int
719 pi_sprog_interface.send_accessory_short_event(2048, True) # Fail - address invalid
720 pi_sprog_interface.send_accessory_short_event(1, "True") # Fail - state invalid
721 pi_sprog_interface.send_accessory_short_event(1, True)
722 pi_sprog_interface.send_accessory_short_event(2, True)
723 pi_sprog_interface.send_accessory_short_event(3, True)
724 pi_sprog_interface.send_accessory_short_event(4, True)
725 pi_sprog_interface.send_accessory_short_event(5, True)
726 pi_sprog_interface.send_accessory_short_event(6, True)
727 pi_sprog_interface.send_accessory_short_event(7, True)
728 pi_sprog_interface.send_accessory_short_event(8, True)
729 system_test_harness.sleep(0.5)
730 pi_sprog_interface.send_accessory_short_event(1, False)
731 system_test_harness.sleep(0.5)
732 pi_sprog_interface.send_accessory_short_event(2, False)
733 system_test_harness.sleep(0.5)
734 pi_sprog_interface.send_accessory_short_event(3, False)
735 system_test_harness.sleep(0.5)
736 pi_sprog_interface.send_accessory_short_event(4, False)
737 system_test_harness.sleep(0.5)
738 pi_sprog_interface.send_accessory_short_event(5, False)
739 system_test_harness.sleep(0.5)
740 pi_sprog_interface.send_accessory_short_event(6, False)
741 system_test_harness.sleep(0.5)
742 pi_sprog_interface.send_accessory_short_event(7, False)
743 system_test_harness.sleep(0.5)
744 pi_sprog_interface.send_accessory_short_event(8, False)
745 system_test_harness.sleep(1.0)
746 print("Library Tests - negative tests - sending commands when DCC power is OFF - 2 Warnings will be generated")
747 assert pi_sprog_interface.request_dcc_power_off()
748 pi_sprog_interface.send_accessory_short_event(8, True)
749 pi_sprog_interface.send_accessory_short_event(8, False)
750 assert pi_sprog_interface.service_mode_read_cv(1) is None
751 assert not pi_sprog_interface.service_mode_write_cv(1,255)
752 print("Library Tests - negative tests - sending commands when port is closed - 4 Warnings will be generated")
753 assert pi_sprog_interface.sprog_disconnect()
754 assert not pi_sprog_interface.request_dcc_power_on()
755 pi_sprog_interface.send_accessory_short_event(8, True)
756 pi_sprog_interface.send_accessory_short_event(8, False)
757 assert pi_sprog_interface.service_mode_read_cv(1) is None
758 assert not pi_sprog_interface.service_mode_write_cv(1,255)
759 assert not pi_sprog_interface.request_dcc_power_off()
760 print("Library Tests - Sprog Shutdown (no errors or warnings)")
761 pi_sprog_interface.sprog_shutdown()
762 pi_sprog_interface.sprog_shutdown()
763 print("----------------------------------------------------------------------------------------")
764 print("")
765 return()
767#---------------------------------------------------------------------------------------------------------
768# Test DCC Control interface
769#---------------------------------------------------------------------------------------------------------
771def run_dcc_control_tests(baud_rate):
772 # Test all functions - including negative tests for parameter validation
773 print("Library Tests - DCC control Tests - connecting to SPROG first")
774 assert pi_sprog_interface.sprog_connect ("/dev/serial0", baud_rate)
775 assert pi_sprog_interface.request_dcc_power_on()
776 print("Library Tests - map_dcc_signal - one Debug message - rest are Errors")
777 assert len(dcc_control.dcc_signal_mappings) == 0
778 assert len(dcc_control.dcc_address_mappings) == 0
779 dcc_control.map_dcc_signal(1, auto_route_inhibit=False,
780 danger = [[1,True], [2,True], [3,False]],
781 proceed = [[1,True], [2,False], [3,False] ],
782 caution = [[1,True], [2,False], [3,False] ],
783 prelim_caution = [[1,False], [2,True], [3,True] ],
784 flash_caution = [[1,False], [2,True], [3,False] ],
785 flash_prelim_caution = [[1,False], [2,False], [3,True] ],
786 MAIN = [[4,True], [5,True], [6,False]],
787 LH1 = [[4,True], [5,False], [6,False] ],
788 LH2 = [[4,True], [5,False], [6,False] ],
789 RH1 = [[4,False], [5,True], [6,True] ],
790 RH2 = [[4,False], [5,True], [6,False] ],
791 NONE = [[4,False], [5,False], [6,True] ],
792 THEATRE = [ ['#', [[4,True], [5,True], [6,False]]],
793 ['1', [[4,True], [5,False], [6,False]] ],
794 ['2', [[4,True], [5,False], [6,False]] ],
795 ['3', [[4,False], [5,True], [6,True]] ],
796 ['4', [[4,False], [5,True], [6,False]] ],
797 ['5', [[4,False], [5,False], [6,True]] ] ],
798 subsidary = 7 )
799 # Negative tests - all will fail with errors
800 dcc_control.map_dcc_signal(0) # Fail - out of range
801 dcc_control.map_dcc_signal(1) # Fail - already exists
802 dcc_control.map_dcc_signal("2") # Fail - not an int
803 dcc_control.map_dcc_signal(3, danger = [[1,True], ["abc",True], [11,"random"], [2048, True]] )
804 dcc_control.map_dcc_signal(4, proceed = [[1,True], ["abc",True], [11,"random"], [2048, True]] )
805 dcc_control.map_dcc_signal(5, caution = [[1,True], ["abc",True], [11,"random"], [2048, True]] )
806 dcc_control.map_dcc_signal(6, prelim_caution = [[1,True], ["abc",True], [11,"random"], [2048, True]] )
807 dcc_control.map_dcc_signal(7, flash_prelim_caution = [[1,True], ["abc",True], [11,"random"], [2048, True]] )
808 dcc_control.map_dcc_signal(8, MAIN = [[1,True], ["abc",True], [11,"random"], [2048, True]] )
809 dcc_control.map_dcc_signal(9, LH1 = [[1,True], ["abc",True], [11,"random"], [2048, True]] )
810 dcc_control.map_dcc_signal(10, RH1 = [[1,True], ["abc",True], [11,"random"], [2048, True]] )
811 dcc_control.map_dcc_signal(11, RH2 = [[1,True], ["abc",True], [11,"random"], [2048, True]] )
812 dcc_control.map_dcc_signal(12, NONE = [[1,True], ["abc",True], [11,"random"], [2048, True]] )
813 dcc_control.map_dcc_signal(13, MAIN = [[1,True], ["abc",True], [11,"random"], [2048, True]] )
814 dcc_control.map_dcc_signal(14, subsidary = 1)
815 dcc_control.map_dcc_signal(15, subsidary = "abc")
816 dcc_control.map_dcc_signal(16, subsidary = 2048)
817 dcc_control.map_dcc_signal(17, THEATRE = [ ['#', [[1,True], ["abc",True], [11,"random"], [2048, True], 2047,[1,2,3]]],
818 ['2', [[1,True], ["abc",True], [11,"random"], [2048, True], 2047,[1,2,3]]] ] )
819 assert len(dcc_control.dcc_signal_mappings) == 1
820 assert len(dcc_control.dcc_address_mappings) == 7
821 print("Library Tests - map_semaphore_signal - one Debug message - rest are Errors")
822 dcc_control.map_semaphore_signal(2, main_signal=10, lh1_signal=11, lh2_signal=12, rh1_signal=13, rh2_signal=14,
823 main_subsidary=15, lh1_subsidary=16, lh2_subsidary=17, rh1_subsidary=18, rh2_subsidary=19,
824 THEATRE = [ ['#', [[20,True], [21,True], [22,False]]],
825 ['1', [[20,True], [21,False], [22,False]] ],
826 ['2', [[20,True], [21,False], [22,False]] ],
827 ['3', [[20,False], [21,True], [22,True]] ],
828 ['4', [[20,False], [21,True], [22,False]] ],
829 ['5', [[20,False], [21,False], [22,True]] ] ])
830 # Negative tests - all will fail with errors
831 dcc_control.map_semaphore_signal(0) # Fail - out of range
832 dcc_control.map_semaphore_signal(2) # Fail - already exists
833 dcc_control.map_semaphore_signal("3") # Fail - not an int
834 dcc_control.map_semaphore_signal(4, main_signal=1, lh1_signal=2, lh2_signal=3, rh1_signal=4, rh2_signal=5)
835 dcc_control.map_semaphore_signal(5, main_signal="ab", lh1_signal="cd", lh2_signal="ef", rh1_signal="gh", rh2_signal="jk")
836 dcc_control.map_semaphore_signal(6, main_signal=2048, lh1_signal=2049, lh2_signal=2050, rh1_signal=2051, rh2_signal=2052)
837 dcc_control.map_semaphore_signal(7, main_subsidary=2048, lh1_subsidary=2049, lh2_subsidary=2050, rh1_subsidary=2051, rh2_subsidary=2052)
838 dcc_control.map_semaphore_signal(8, main_subsidary="ab", lh1_subsidary="cd", lh2_subsidary="ef", rh1_subsidary="gh", rh2_subsidary="jk")
839 dcc_control.map_semaphore_signal(9, main_subsidary=10, lh1_subsidary=11, lh2_subsidary=12, rh1_subsidary=13, rh2_subsidary=14)
840 dcc_control.map_semaphore_signal(10, THEATRE = [ ['#', [[1,True], ["abc",True], [11,"random"], [2048, True], 2047,[1,2,3]]],
841 ['2', [[1,True], ["abc",True], [11,"random"], [2048, True], 2047,[1,2,3]]] ] )
842 assert len(dcc_control.dcc_signal_mappings) == 2
843 assert len(dcc_control.dcc_address_mappings) == 20
844 print("Library Tests - map_dcc_point - Two Debug messages - rest are Errors")
845 assert len(dcc_control.dcc_point_mappings) == 0
846 dcc_control.map_dcc_point(1, 30, False)
847 dcc_control.map_dcc_point(2, 31, True)
848 dcc_control.map_dcc_point(0, 32, False) # Fail - Invalid ID
849 dcc_control.map_dcc_point(1, 32, False) # Fail - Duplicate ID
850 dcc_control.map_dcc_point("3", 32, False) # Fail - ID not an int
851 dcc_control.map_dcc_point(4, 30, False) # Fail - address already in use
852 dcc_control.map_dcc_point(5, 10, False) # Fail - address already in use
853 dcc_control.map_dcc_point(6, "abc", False) # Fail - address not a str
854 dcc_control.map_dcc_point(6, 2048, False) # Fail - Invalid address
855 dcc_control.map_dcc_point(7, 33, "True") # Fail - Invalid reversed flag
856 assert len(dcc_control.dcc_point_mappings) == 2
857 assert len(dcc_control.dcc_address_mappings) == 22
858 print("Library Tests - get_dcc_address_mappings (no errors or warnings should be generated)")
859 mappings = dcc_control.get_dcc_address_mappings()
860 assert mappings == {1: ['Signal', 1], 2: ['Signal', 1], 3: ['Signal', 1], 4: ['Signal', 1],
861 5: ['Signal', 1], 6: ['Signal', 1], 7: ['Signal', 1], 10: ['Signal', 2],
862 15: ['Signal', 2], 11: ['Signal', 2], 16: ['Signal', 2], 13: ['Signal', 2],
863 18: ['Signal', 2], 12: ['Signal', 2], 17: ['Signal', 2], 14: ['Signal', 2],
864 19: ['Signal', 2], 20: ['Signal', 2], 21: ['Signal', 2], 22: ['Signal', 2],
865 30: ['Point', 1], 31: ['Point', 2]}
866 print("Library Tests - dcc_address_mapping - 2 Errors should be generated)")
867 assert dcc_control.dcc_address_mapping(1) == ['Signal', 1]
868 assert dcc_control.dcc_address_mapping(10) == ['Signal', 2]
869 assert dcc_control.dcc_address_mapping(30) == ['Point', 1]
870 assert dcc_control.dcc_address_mapping(31) == ['Point', 2]
871 assert dcc_control.dcc_address_mapping(40) is None
872 assert dcc_control.dcc_address_mapping("40") is None # Error - not an int
873 assert dcc_control.dcc_address_mapping(2048) is None # Error - out of range
874 print("Library Tests - update_dcc_point (no errors or warnings - but DCC commands should be sent)")
875 dcc_control.update_dcc_point(1, True)
876 dcc_control.update_dcc_point(1, False)
877 dcc_control.update_dcc_point(2, True)
878 dcc_control.update_dcc_point(2, False)
879 print("Library Tests - update_dcc_signal_aspects - 1 Error - DCC commands should be sent")
880 dcc_control.update_dcc_signal_aspects(2, signals_common.signal_state_type.DANGER) # Error - wrong type
881 dcc_control.update_dcc_signal_aspects(1, signals_common.signal_state_type.DANGER)
882 dcc_control.update_dcc_signal_aspects(1, signals_common.signal_state_type.PROCEED)
883 dcc_control.update_dcc_signal_aspects(1, signals_common.signal_state_type.CAUTION)
884 dcc_control.update_dcc_signal_aspects(1, signals_common.signal_state_type.PRELIM_CAUTION)
885 dcc_control.update_dcc_signal_aspects(1, signals_common.signal_state_type.FLASH_CAUTION)
886 dcc_control.update_dcc_signal_aspects(1, signals_common.signal_state_type.FLASH_PRELIM_CAUTION)
887 dcc_control.update_dcc_signal_element(1, True, element="main_subsidary")
888 dcc_control.update_dcc_signal_aspects(3, signals_common.signal_state_type.DANGER)
889 print("Library Tests - update_dcc_signal_element - 1 Error - DCC commands should be sent")
890 dcc_control.update_dcc_signal_element(1, True, element="main_signal")
891 dcc_control.update_dcc_signal_element(1, True, element="main_subsidary")
892 dcc_control.update_dcc_signal_element(2, True, element="main_signal")
893 dcc_control.update_dcc_signal_element(2, True, element="main_subsidary")
894 dcc_control.update_dcc_signal_element(2, True, element="lh1_signal")
895 dcc_control.update_dcc_signal_element(2, True, element="lh1_subsidary")
896 dcc_control.update_dcc_signal_element(2, True, element="lh2_signal")
897 dcc_control.update_dcc_signal_element(2, True, element="lh2_subsidary")
898 dcc_control.update_dcc_signal_element(2, True, element="rh1_signal")
899 dcc_control.update_dcc_signal_element(2, True, element="rh1_subsidary")
900 dcc_control.update_dcc_signal_element(2, True, element="rh2_signal")
901 dcc_control.update_dcc_signal_element(2, True, element="rh2_subsidary")
902 print("Library Tests - update_dcc_signal_route - 1 Error - DCC commands should be sent)")
903 dcc_control.update_dcc_signal_route(2,signals_common.route_type.MAIN, True, False)
904 dcc_control.update_dcc_signal_route(1,signals_common.route_type.MAIN, True, False)
905 dcc_control.update_dcc_signal_route(1,signals_common.route_type.LH1, True, False)
906 dcc_control.update_dcc_signal_route(1,signals_common.route_type.LH2, True, False)
907 dcc_control.update_dcc_signal_route(1,signals_common.route_type.RH1, True, False)
908 dcc_control.update_dcc_signal_route(1,signals_common.route_type.RH2, True, False)
909 dcc_control.update_dcc_signal_route(1,signals_common.route_type.MAIN, True, True)
910 dcc_control.update_dcc_signal_route(1,signals_common.route_type.MAIN, False, True)
911 dcc_control.update_dcc_signal_route(1,signals_common.route_type.MAIN, False, False)
912 print("Library Tests - update_dcc_signal_theatre (no errors or warnings - DCC commands should be sent)")
913 dcc_control.update_dcc_signal_theatre(1,"#", True, False)
914 dcc_control.update_dcc_signal_theatre(1,"1", True, False)
915 dcc_control.update_dcc_signal_theatre(1,"2", True, False)
916 dcc_control.update_dcc_signal_theatre(1,"3", True, False)
917 dcc_control.update_dcc_signal_theatre(1,"4", True, False)
918 dcc_control.update_dcc_signal_theatre(1,"5", True, False)
919 dcc_control.update_dcc_signal_theatre(1,"1", True, True)
920 dcc_control.update_dcc_signal_theatre(1,"1", False, True)
921 dcc_control.update_dcc_signal_theatre(1,"1", False, False)
922 print("Library Tests - set_node_to_publish_dcc_commands - 1 Error will be generated ")
923 dcc_control.set_node_to_publish_dcc_commands("True") # Error
924 dcc_control.set_node_to_publish_dcc_commands(True)
925 print("Library Tests - subscribe_to_dcc_command_feed - 1 Error will be generated")
926 dcc_control.subscribe_to_dcc_command_feed(100) # Error
927 dcc_control.subscribe_to_dcc_command_feed("Box1")
928 print("Library Tests - reset_mqtt_configuration - No warnings or errors")
929 dcc_control.reset_mqtt_configuration()
930 print("Library Tests - handle_mqtt_dcc_accessory_short_event - 3 Errors - DCC Commands should be sent out")
931 dcc_control.handle_mqtt_dcc_accessory_short_event({"sourceidentifier": "box1-200", "dccaddress": 1000}) # Error
932 dcc_control.handle_mqtt_dcc_accessory_short_event({"sourceidentifier": "box1-200", "dccstate": True}) # Error
933 dcc_control.handle_mqtt_dcc_accessory_short_event({"dccaddress": 1000, "dccstate": True}) # Error
934 dcc_control.handle_mqtt_dcc_accessory_short_event({"sourceidentifier": "box1-200", "dccaddress": 1000, "dccstate": True}) # Valid
935 dcc_control.handle_mqtt_dcc_accessory_short_event({"sourceidentifier": "box1-200", "dccaddress": 1000, "dccstate": False}) # Valid
936 print("Library Tests - delete_point_mapping - 2 Errors shoould be generated")
937 assert len(dcc_control.dcc_point_mappings) == 2
938 assert len(dcc_control.dcc_address_mappings) == 22
939 dcc_control.delete_point_mapping("100") # Error
940 dcc_control.delete_point_mapping(5) # Error (does not exist)
941 dcc_control.delete_point_mapping(1)
942 assert len(dcc_control.dcc_point_mappings) == 1
943 assert len(dcc_control.dcc_address_mappings) == 21
944 dcc_control.delete_point_mapping(2)
945 assert len(dcc_control.dcc_point_mappings) == 0
946 assert len(dcc_control.dcc_address_mappings) == 20
947 print("Library Tests - delete_signal_mapping - 2 Errors shoould be generated")
948 assert len(dcc_control.dcc_signal_mappings) == 2
949 dcc_control.delete_signal_mapping("100") # Error
950 dcc_control.delete_signal_mapping(5) # Error (does not exist)
951 dcc_control.delete_signal_mapping(2)
952 assert len(dcc_control.dcc_signal_mappings) == 1
953 assert len(dcc_control.dcc_address_mappings) == 7
954 dcc_control.delete_signal_mapping(1)
955 assert len(dcc_control.dcc_signal_mappings) == 0
956 assert len(dcc_control.dcc_address_mappings) == 0
957 print("Library Tests - DCC control Tests - disconnecting from SPROG")
958 system_test_harness.sleep(1.0) # Give the SPROG a chance to send all DCC commands
959 assert pi_sprog_interface.request_dcc_power_off()
960 assert pi_sprog_interface.sprog_disconnect()
961 print("----------------------------------------------------------------------------------------")
962 print("")
963 return()
965#---------------------------------------------------------------------------------------------------------
966# Test MQTT interface
967#---------------------------------------------------------------------------------------------------------
969def shutdown_callback():
970 print("Library Tests - MQTT shutdown callback received")
972def message_callback(message):
973 print("Library Tests - MQTT message received: "+str(message))
975def run_mqtt_interface_tests():
976 # Test all functions - including negative tests for parameter validation
977 print("Library Tests - MQTT Interface Tests")
978 print("Library Tests - split_remote_item_identifier")
979 assert mqtt_interface.split_remote_item_identifier(123) is None
980 assert mqtt_interface.split_remote_item_identifier("box111") is None
981 assert mqtt_interface.split_remote_item_identifier("box1-abc") is None
982 assert mqtt_interface.split_remote_item_identifier("box1-0") is None
983 assert mqtt_interface.split_remote_item_identifier("box1-999") is None
984 assert mqtt_interface.split_remote_item_identifier("box1-99") == ["box1", 99]
985 print("Library Tests - configure_mqtt_client - 5 Errors should be generated")
986 mqtt_interface.configure_mqtt_client(100,"node1", False, False, False, shutdown_callback) # error
987 mqtt_interface.configure_mqtt_client("network1",100, False, False, False, shutdown_callback) # error
988 mqtt_interface.configure_mqtt_client("network1","node1", "False", False, False, shutdown_callback) # error
989 mqtt_interface.configure_mqtt_client("network1","node1", False, "False", False, shutdown_callback) # error
990 mqtt_interface.configure_mqtt_client("network1","node1", False, False, "False", shutdown_callback) # error
991 mqtt_interface.configure_mqtt_client("network1","node1", True, True, True, shutdown_callback) # Success
992 print("Library Tests - mqtt_broker_connect - 4 Errors should be generated")
993 assert not mqtt_interface.mqtt_broker_connect(127,1883) # Fail
994 assert not mqtt_interface.mqtt_broker_connect("127.0.0.1","1883") # Fail
995 assert not mqtt_interface.mqtt_broker_connect("127.0.0.1",1883, 100, "password1") # Fail
996 assert not mqtt_interface.mqtt_broker_connect("127.0.0.1",1883, "user1", 100) # Fail
997 assert mqtt_interface.mqtt_broker_connect("127.0.0.1",1883, "user1", "password1") # success
998 system_test_harness.sleep(0.2)
999 print("Library Tests - mqtt_broker_disconnect (and then re-connect")
1000 assert mqtt_interface.mqtt_broker_disconnect()
1001 assert mqtt_interface.mqtt_broker_connect("127.0.0.1",1883, "user1", "password1") # success
1002 system_test_harness.sleep(0.2)
1003 print("Library Tests - subscribe_to_mqtt_messages")
1004 mqtt_interface.subscribe_to_mqtt_messages("test_messages_1", "node1", 1, message_callback)
1005 mqtt_interface.subscribe_to_mqtt_messages("test_messages_2", "node1", 1, message_callback, subtopics=True)
1006 system_test_harness.sleep(0.2)
1007 print("Library Tests - send_mqtt_message")
1008 mqtt_interface.send_mqtt_message("test_messages_1", 1, {"data1":123, "data2":"abc"}, log_message="LOG MESSAGE 1")
1009 mqtt_interface.send_mqtt_message("test_messages_1", 1, {"data1":456, "data2":"def"}, log_message="LOG MESSAGE 2")
1010 mqtt_interface.send_mqtt_message("test_messages_2", 1, {"data1":123, "data2":"abc"}, log_message="LOG MESSAGE 3", subtopic="sub1")
1011 mqtt_interface.send_mqtt_message("test_messages_2", 1, {"data1":456, "data2":"def"}, log_message="LOG MESSAGE 4", subtopic="sub2")
1012 system_test_harness.sleep(0.2)
1013 print("Library Tests - unsubscribe_from_message_type")
1014 mqtt_interface.unsubscribe_from_message_type("test_messages_1")
1015 system_test_harness.sleep(0.2)
1016 mqtt_interface.send_mqtt_message("test_messages_1", 1, {"data1":123, "data2":"abc"}, log_message="LOG MESSAGE 1")
1017 mqtt_interface.send_mqtt_message("test_messages_1", 1, {"data1":456, "data2":"def"}, log_message="LOG MESSAGE 2")
1018 print("Library Tests - mqtt_shutdown")
1019 mqtt_interface.mqtt_shutdown()
1020 system_test_harness.sleep(0.2)
1021 print("----------------------------------------------------------------------------------------")
1022 print("")
1023 return()
1025#---------------------------------------------------------------------------------------------------------
1026# Run all library Tests
1027#---------------------------------------------------------------------------------------------------------
1029def run_all_basic_library_tests(shutdown:bool=False):
1030 baud_rate = 115200 # change to 460800 for Pi Sprog V2
1031 logging.getLogger().setLevel(logging.DEBUG)
1032 run_track_sensor_library_tests()
1033 run_gpio_sensor_library_tests()
1034 run_point_library_tests()
1035 run_instrument_library_tests()
1036 run_pi_sprog_interface_tests(baud_rate)
1037 run_dcc_control_tests(baud_rate)
1038 run_mqtt_interface_tests()
1039 logging.getLogger().setLevel(logging.WARNING)
1040 if shutdown: system_test_harness.report_results()
1042if __name__ == "__main__": 1042 ↛ 1043line 1042 didn't jump to line 1043, because the condition on line 1042 was never true
1043 system_test_harness.start_application(lambda:run_all_basic_library_tests(shutdown=True))
1045###############################################################################################################################