wiliot-certificate 4.4.3__py3-none-any.whl → 4.5.0a1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (295) hide show
  1. {brg_certificate → certificate}/ag/wlt_cmd_if.html +10 -4
  2. {brg_certificate → certificate}/ag/wlt_types_ag.py +1878 -519
  3. {brg_certificate → certificate}/ag/wlt_types_ag_jsons/brg2brg_ota.json +69 -0
  4. {brg_certificate → certificate}/ag/wlt_types_ag_jsons/brg2gw_hb.json +109 -0
  5. {brg_certificate → certificate}/ag/wlt_types_ag_jsons/brg2gw_hb_sleep.json +45 -0
  6. {brg_certificate → certificate}/ag/wlt_types_ag_jsons/calibration.json +96 -0
  7. {brg_certificate → certificate}/ag/wlt_types_ag_jsons/custom.json +99 -0
  8. {brg_certificate → certificate}/ag/wlt_types_ag_jsons/datapath.json +241 -13
  9. {brg_certificate → certificate}/ag/wlt_types_ag_jsons/energy2400.json +120 -0
  10. {brg_certificate → certificate}/ag/wlt_types_ag_jsons/energySub1g.json +96 -0
  11. {brg_certificate → certificate}/ag/wlt_types_ag_jsons/externalSensor.json +135 -6
  12. {brg_certificate → certificate}/ag/wlt_types_ag_jsons/interface.json +157 -0
  13. {brg_certificate → certificate}/ag/wlt_types_ag_jsons/powerManagement.json +205 -0
  14. brg_certificate/ag/wlt_types_ag_jsons/unified_echo_pkt.json → certificate/ag/wlt_types_ag_jsons/unified_echo_ext_pkt.json +27 -11
  15. certificate/ag/wlt_types_ag_jsons/unified_echo_pkt.json +175 -0
  16. certificate/ag/wlt_types_ag_jsons/unified_sensor_pkt.json +65 -0
  17. certificate/cert_common.py +1459 -0
  18. certificate/cert_config.py +455 -0
  19. {brg_certificate → certificate}/cert_data_sim.py +131 -46
  20. {brg_certificate → certificate}/cert_defines.py +120 -128
  21. {brg_certificate → certificate}/cert_gw_sim.py +151 -49
  22. {brg_certificate → certificate}/cert_mqtt.py +164 -59
  23. {brg_certificate → certificate}/cert_prints.py +34 -33
  24. {brg_certificate → certificate}/cert_protobuf.py +15 -6
  25. {brg_certificate → certificate}/cert_results.py +205 -48
  26. certificate/cert_utils.py +622 -0
  27. certificate/certificate.py +198 -0
  28. certificate/certificate_cli.py +79 -0
  29. certificate/certificate_eth_test_list.txt +74 -0
  30. certificate/certificate_sanity_test_list.txt +65 -0
  31. certificate/certificate_test_list.txt +75 -0
  32. {brg_certificate → certificate}/tests/calibration/interval_test/interval_test.json +2 -2
  33. {brg_certificate → certificate}/tests/calibration/interval_test/interval_test.py +7 -6
  34. certificate/tests/calibration/output_power_test/output_power_test.json +22 -0
  35. certificate/tests/calibration/output_power_test/output_power_test.py +39 -0
  36. {brg_certificate → certificate}/tests/calibration/pattern_test/pattern_test.json +1 -1
  37. {brg_certificate → certificate}/tests/calibration/pattern_test/pattern_test.py +20 -15
  38. certificate/tests/cloud_connectivity/acl_ext_adv_test/acl_ext_adv_test.json +14 -0
  39. certificate/tests/cloud_connectivity/acl_ext_adv_test/acl_ext_adv_test.py +140 -0
  40. certificate/tests/cloud_connectivity/acl_test/acl_test.json +14 -0
  41. certificate/tests/cloud_connectivity/acl_test/acl_test.py +98 -0
  42. certificate/tests/cloud_connectivity/brg_ota_test/brg_ota_test.json +18 -0
  43. certificate/tests/cloud_connectivity/brg_ota_test/brg_ota_test.py +39 -0
  44. certificate/tests/cloud_connectivity/channel_scan_behaviour_test/channel_scan_behaviour_test.json +18 -0
  45. certificate/tests/cloud_connectivity/channel_scan_behaviour_test/channel_scan_behaviour_test.py +215 -0
  46. certificate/tests/cloud_connectivity/connection_test/connection_test.json +17 -0
  47. certificate/tests/cloud_connectivity/connection_test/connection_test.py +74 -0
  48. certificate/tests/cloud_connectivity/downlink_test/downlink_test.json +20 -0
  49. certificate/tests/cloud_connectivity/downlink_test/downlink_test.py +204 -0
  50. certificate/tests/cloud_connectivity/ext_adv_stress_test/ext_adv_stress_test.json +16 -0
  51. certificate/tests/cloud_connectivity/ext_adv_stress_test/ext_adv_stress_test.py +98 -0
  52. certificate/tests/cloud_connectivity/reboot_test/reboot_test.json +17 -0
  53. certificate/tests/cloud_connectivity/reboot_test/reboot_test.py +57 -0
  54. certificate/tests/cloud_connectivity/registration_test/registration_test.json +19 -0
  55. certificate/tests/cloud_connectivity/registration_test/registration_test.py +384 -0
  56. certificate/tests/cloud_connectivity/registration_test/registration_test_cli.py +90 -0
  57. certificate/tests/cloud_connectivity/stress_test/stress_test.json +16 -0
  58. certificate/tests/cloud_connectivity/stress_test/stress_test.py +97 -0
  59. certificate/tests/cloud_connectivity/uplink_ext_adv_test/uplink_ext_adv_test.json +24 -0
  60. certificate/tests/cloud_connectivity/uplink_ext_adv_test/uplink_ext_adv_test.py +93 -0
  61. certificate/tests/cloud_connectivity/uplink_test/uplink_test.json +19 -0
  62. certificate/tests/cloud_connectivity/uplink_test/uplink_test.py +161 -0
  63. {brg_certificate → certificate}/tests/datapath/aging_test/aging_test.json +1 -1
  64. certificate/tests/datapath/aging_test/aging_test.py +138 -0
  65. certificate/tests/datapath/event_ble5_test/event_ble5_test.json +16 -0
  66. certificate/tests/datapath/event_ble5_test/event_ble5_test.py +95 -0
  67. certificate/tests/datapath/event_test/event_test.json +16 -0
  68. certificate/tests/datapath/event_test/event_test.py +85 -0
  69. {brg_certificate → certificate}/tests/datapath/num_of_tags_test/num_of_tags_test.json +1 -1
  70. {brg_certificate → certificate}/tests/datapath/num_of_tags_test/num_of_tags_test.py +10 -8
  71. certificate/tests/datapath/output_power_test/output_power_test.json +22 -0
  72. {brg_certificate → certificate}/tests/datapath/output_power_test/output_power_test.py +17 -6
  73. {brg_certificate → certificate}/tests/datapath/pacer_interval_ble5_test/pacer_interval_ble5_test.json +1 -1
  74. {brg_certificate → certificate}/tests/datapath/pacer_interval_ble5_test/pacer_interval_ble5_test.py +10 -8
  75. {brg_certificate → certificate}/tests/datapath/pacer_interval_test/pacer_interval_test.json +1 -1
  76. {brg_certificate → certificate}/tests/datapath/pacer_interval_test/pacer_interval_test.py +9 -7
  77. {brg_certificate → certificate}/tests/datapath/pattern_test/pattern_test.json +2 -2
  78. {brg_certificate → certificate}/tests/datapath/pattern_test/pattern_test.py +18 -6
  79. certificate/tests/datapath/pkt_filter_ble5_chl21_test/pkt_filter_ble5_chl21_test.json +19 -0
  80. certificate/tests/datapath/pkt_filter_ble5_chl21_test/pkt_filter_ble5_chl21_test.py +61 -0
  81. {brg_certificate → certificate}/tests/datapath/pkt_filter_ble5_test/pkt_filter_ble5_test.json +1 -1
  82. {brg_certificate → certificate}/tests/datapath/pkt_filter_ble5_test/pkt_filter_ble5_test.py +11 -10
  83. certificate/tests/datapath/pkt_filter_brg2gw_ext_adv_test/pkt_filter_brg2gw_ext_adv_test.json +18 -0
  84. certificate/tests/datapath/pkt_filter_brg2gw_ext_adv_test/pkt_filter_brg2gw_ext_adv_test.py +83 -0
  85. {brg_certificate → certificate}/tests/datapath/pkt_filter_gen3_test/pkt_filter_gen3_test.json +1 -1
  86. {brg_certificate → certificate}/tests/datapath/pkt_filter_gen3_test/pkt_filter_gen3_test.py +10 -9
  87. {brg_certificate → certificate}/tests/datapath/pkt_filter_test/pkt_filter_test.json +1 -1
  88. {brg_certificate → certificate}/tests/datapath/pkt_filter_test/pkt_filter_test.py +10 -9
  89. {brg_certificate → certificate}/tests/datapath/rssi_threshold_test/rssi_threshold_test.json +1 -1
  90. {brg_certificate → certificate}/tests/datapath/rssi_threshold_test/rssi_threshold_test.py +9 -8
  91. brg_certificate/tests/datapath/output_power_test/output_power_test.json → certificate/tests/datapath/rx_channel_hopping_test/rx_channel_hopping_test.json +5 -4
  92. certificate/tests/datapath/rx_channel_hopping_test/rx_channel_hopping_test.py +77 -0
  93. {brg_certificate → certificate}/tests/datapath/rx_channel_test/rx_channel_test.json +2 -2
  94. {brg_certificate → certificate}/tests/datapath/rx_channel_test/rx_channel_test.py +7 -6
  95. {brg_certificate → certificate}/tests/datapath/rx_rate_gen2_test/rx_rate_gen2_test.json +7 -7
  96. {brg_certificate → certificate}/tests/datapath/rx_rate_gen2_test/rx_rate_gen2_test.py +112 -72
  97. {brg_certificate → certificate}/tests/datapath/rx_rate_gen3_test/rx_rate_gen3_test.json +7 -7
  98. {brg_certificate → certificate}/tests/datapath/rx_rate_gen3_test/rx_rate_gen3_test.py +112 -72
  99. {brg_certificate → certificate}/tests/datapath/stress_gen3_test/stress_gen3_test.json +3 -3
  100. {brg_certificate → certificate}/tests/datapath/stress_gen3_test/stress_gen3_test.py +12 -11
  101. {brg_certificate → certificate}/tests/datapath/stress_test/stress_test.json +3 -3
  102. {brg_certificate → certificate}/tests/datapath/stress_test/stress_test.py +12 -11
  103. {brg_certificate → certificate}/tests/datapath/tx_repetition_test/tx_repetition_test.json +2 -1
  104. {brg_certificate → certificate}/tests/datapath/tx_repetition_test/tx_repetition_test.py +14 -13
  105. certificate/tests/edge_mgmt/action_blink_test/action_blink_test.json +14 -0
  106. certificate/tests/edge_mgmt/action_blink_test/action_blink_test.py +24 -0
  107. certificate/tests/edge_mgmt/action_get_battery_sensor_test/action_get_battery_sensor_test.json +14 -0
  108. certificate/tests/edge_mgmt/action_get_battery_sensor_test/action_get_battery_sensor_test.py +43 -0
  109. certificate/tests/edge_mgmt/action_get_module_test/action_get_module_test.json +14 -0
  110. certificate/tests/edge_mgmt/action_get_module_test/action_get_module_test.py +42 -0
  111. certificate/tests/edge_mgmt/action_get_pof_data_test/action_get_pof_data_test.json +14 -0
  112. certificate/tests/edge_mgmt/action_get_pof_data_test/action_get_pof_data_test.py +44 -0
  113. certificate/tests/edge_mgmt/action_gw_hb_test/action_gw_hb_test.json +15 -0
  114. certificate/tests/edge_mgmt/action_gw_hb_test/action_gw_hb_test.py +42 -0
  115. certificate/tests/edge_mgmt/action_reboot_test/action_reboot_test.json +14 -0
  116. certificate/tests/edge_mgmt/action_reboot_test/action_reboot_test.py +49 -0
  117. certificate/tests/edge_mgmt/action_restore_defaults_test/action_restore_defaults_test.json +14 -0
  118. certificate/tests/edge_mgmt/action_restore_defaults_test/action_restore_defaults_test.py +102 -0
  119. certificate/tests/edge_mgmt/action_send_hb_test/action_send_hb_test.json +14 -0
  120. certificate/tests/edge_mgmt/action_send_hb_test/action_send_hb_test.py +41 -0
  121. {brg_certificate → certificate}/tests/edge_mgmt/periodic_msgs_test/periodic_msgs_test.json +2 -2
  122. {brg_certificate → certificate}/tests/edge_mgmt/periodic_msgs_test/periodic_msgs_test.py +22 -11
  123. {brg_certificate → certificate}/tests/energy2400/duty_cycle_test/duty_cycle_test.json +1 -1
  124. {brg_certificate → certificate}/tests/energy2400/duty_cycle_test/duty_cycle_test.py +7 -6
  125. certificate/tests/energy2400/output_power_test/output_power_test.json +22 -0
  126. {brg_certificate → certificate}/tests/energy2400/output_power_test/output_power_test.py +17 -6
  127. {brg_certificate → certificate}/tests/energy2400/pattern_test/pattern_test.json +1 -1
  128. {brg_certificate → certificate}/tests/energy2400/pattern_test/pattern_test.py +7 -6
  129. certificate/tests/energy2400/signal_indicator_ble5_test/signal_indicator_ble5_test.json +25 -0
  130. certificate/tests/energy2400/signal_indicator_ble5_test/signal_indicator_ble5_test.py +378 -0
  131. brg_certificate/tests/energy2400/signal_indicator_ble5_10_500k_test/signal_indicator_ble5_10_500k_test.json → certificate/tests/energy2400/signal_indicator_ext_adv_test/signal_indicator_ext_adv_test.json +3 -3
  132. brg_certificate/tests/energy2400/signal_indicator_ble5_10_500k_test/signal_indicator_ble5_10_500k_test.py → certificate/tests/energy2400/signal_indicator_ext_adv_test/signal_indicator_ext_adv_test.py +97 -87
  133. certificate/tests/energy2400/signal_indicator_test/signal_indicator_test.json +23 -0
  134. certificate/tests/energy2400/signal_indicator_test/signal_indicator_test.py +350 -0
  135. {brg_certificate → certificate}/tests/energy_sub1g/duty_cycle_test/duty_cycle_test.json +1 -1
  136. {brg_certificate → certificate}/tests/energy_sub1g/duty_cycle_test/duty_cycle_test.py +7 -6
  137. {brg_certificate → certificate}/tests/energy_sub1g/pattern_test/pattern_test.json +1 -1
  138. {brg_certificate → certificate}/tests/energy_sub1g/pattern_test/pattern_test.py +7 -6
  139. {brg_certificate → certificate}/tests/pwr_mgmt/pwr_mgmt_test/pwr_mgmt_test.json +1 -1
  140. {brg_certificate → certificate}/tests/pwr_mgmt/pwr_mgmt_test/pwr_mgmt_test.py +10 -10
  141. {brg_certificate → certificate}/tests/sensors/ext_sensor_test/ext_sensor_test.json +4 -4
  142. certificate/tests/sensors/ext_sensor_test/ext_sensor_test.py +455 -0
  143. certificate/wlt_types.py +122 -0
  144. {gw_certificate → common}/api_if/202/status.json +6 -0
  145. {gw_certificate → common}/api_if/203/status.json +6 -0
  146. {gw_certificate → common}/api_if/204/status.json +6 -0
  147. common/api_if/206/data.json +85 -0
  148. common/api_if/206/status.json +69 -0
  149. common/api_if/api_validation.py +85 -0
  150. common/web/templates/generator.html +148 -0
  151. common/web/templates/index.html +20 -0
  152. common/web/templates/menu.html +54 -0
  153. common/web/templates/parser.html +53 -0
  154. {brg_certificate/ag → common/web/templates}/wlt_types.html +1216 -191
  155. common/web/web_utils.py +377 -0
  156. {brg_certificate → common}/wltPb_pb2.py +14 -12
  157. {gw_certificate/common → common}/wltPb_pb2.pyi +16 -2
  158. gui_certificate/gui_certificate_cli.py +14 -0
  159. gui_certificate/server.py +1062 -0
  160. gui_certificate/templates/cert_run.html +1207 -0
  161. wiliot_certificate-4.5.0a1.dist-info/METADATA +110 -0
  162. wiliot_certificate-4.5.0a1.dist-info/RECORD +182 -0
  163. {wiliot_certificate-4.4.3.dist-info → wiliot_certificate-4.5.0a1.dist-info}/WHEEL +1 -1
  164. wiliot_certificate-4.5.0a1.dist-info/entry_points.txt +5 -0
  165. wiliot_certificate-4.5.0a1.dist-info/top_level.txt +3 -0
  166. brg_certificate/ag/energous_v0_defines.py +0 -925
  167. brg_certificate/ag/energous_v1_defines.py +0 -931
  168. brg_certificate/ag/energous_v2_defines.py +0 -925
  169. brg_certificate/ag/energous_v3_defines.py +0 -925
  170. brg_certificate/ag/energous_v4_defines.py +0 -925
  171. brg_certificate/ag/fanstel_lan_v0_defines.py +0 -925
  172. brg_certificate/ag/fanstel_lte_v0_defines.py +0 -925
  173. brg_certificate/ag/fanstel_wifi_v0_defines.py +0 -925
  174. brg_certificate/ag/minew_lte_v0_defines.py +0 -925
  175. brg_certificate/ag/wlt_types_ag_jsons/unified_echo_ext_pkt.json +0 -61
  176. brg_certificate/brg_certificate.py +0 -225
  177. brg_certificate/brg_certificate_cli.py +0 -63
  178. brg_certificate/cert_common.py +0 -923
  179. brg_certificate/cert_config.py +0 -402
  180. brg_certificate/cert_utils.py +0 -362
  181. brg_certificate/certificate_bcc_sanity_test_list.txt +0 -40
  182. brg_certificate/certificate_bcc_test_list.txt +0 -48
  183. brg_certificate/certificate_sanity_test_list.txt +0 -43
  184. brg_certificate/certificate_test_list.txt +0 -53
  185. brg_certificate/config/eclipse.json +0 -10
  186. brg_certificate/config/hivemq.json +0 -10
  187. brg_certificate/config/mosquitto.json +0 -10
  188. brg_certificate/config/mosquitto.md +0 -95
  189. brg_certificate/config/wiliot-dev.json +0 -10
  190. brg_certificate/restore_brg.py +0 -61
  191. brg_certificate/tests/calibration/output_power_test/output_power_test.json +0 -16
  192. brg_certificate/tests/calibration/output_power_test/output_power_test.py +0 -28
  193. brg_certificate/tests/datapath/aging_test/aging_test.py +0 -143
  194. brg_certificate/tests/datapath/pacer_interval_tags_count_test/pacer_interval_tags_count_test.json +0 -16
  195. brg_certificate/tests/datapath/pacer_interval_tags_count_test/pacer_interval_tags_count_test.py +0 -73
  196. brg_certificate/tests/datapath/tx_repetition_algo_test/tx_repetition_algo_test.json +0 -17
  197. brg_certificate/tests/datapath/tx_repetition_algo_test/tx_repetition_algo_test.py +0 -118
  198. brg_certificate/tests/edge_mgmt/actions_test/actions_test.json +0 -14
  199. brg_certificate/tests/edge_mgmt/actions_test/actions_test.py +0 -396
  200. brg_certificate/tests/edge_mgmt/brg2brg_ota_ble5_test/brg2brg_ota_ble5_test.json +0 -20
  201. brg_certificate/tests/edge_mgmt/brg2brg_ota_ble5_test/brg2brg_ota_ble5_test.py +0 -94
  202. brg_certificate/tests/edge_mgmt/brg2brg_ota_test/brg2brg_ota_test.json +0 -19
  203. brg_certificate/tests/edge_mgmt/brg2brg_ota_test/brg2brg_ota_test.py +0 -87
  204. brg_certificate/tests/edge_mgmt/leds_test/leds_test.json +0 -17
  205. brg_certificate/tests/edge_mgmt/leds_test/leds_test.py +0 -223
  206. brg_certificate/tests/edge_mgmt/ota_test/ota_test.json +0 -17
  207. brg_certificate/tests/edge_mgmt/ota_test/ota_test.py +0 -128
  208. brg_certificate/tests/energy2400/output_power_test/output_power_test.json +0 -16
  209. brg_certificate/tests/energy2400/signal_indicator_ble5_10_250k_test/signal_indicator_ble5_10_250k_test.json +0 -20
  210. brg_certificate/tests/energy2400/signal_indicator_ble5_10_250k_test/signal_indicator_ble5_10_250k_test.py +0 -321
  211. brg_certificate/tests/energy2400/signal_indicator_sub1g_2_4_test/signal_indicator_sub1g_2_4_test.json +0 -20
  212. brg_certificate/tests/energy2400/signal_indicator_sub1g_2_4_test/signal_indicator_sub1g_2_4_test.py +0 -141
  213. brg_certificate/tests/energy2400/signal_indicator_test/signal_indicator_test.json +0 -20
  214. brg_certificate/tests/energy2400/signal_indicator_test/signal_indicator_test.py +0 -276
  215. brg_certificate/tests/energy_sub1g/signal_indicator_functionality_test/signal_indicator_functionality_test.json +0 -20
  216. brg_certificate/tests/energy_sub1g/signal_indicator_functionality_test/signal_indicator_functionality_test.py +0 -390
  217. brg_certificate/tests/energy_sub1g/signal_indicator_test/signal_indicator_test.json +0 -16
  218. brg_certificate/tests/energy_sub1g/signal_indicator_test/signal_indicator_test.py +0 -28
  219. brg_certificate/tests/sensors/ext_sensor_test/ext_sensor_test.py +0 -305
  220. brg_certificate/wltPb_pb2.pyi +0 -234
  221. brg_certificate/wlt_types.py +0 -113
  222. gw_certificate/ag/ut_defines.py +0 -364
  223. gw_certificate/ag/wlt_types.py +0 -85
  224. gw_certificate/ag/wlt_types_ag.py +0 -5310
  225. gw_certificate/ag/wlt_types_data.py +0 -64
  226. gw_certificate/api/extended_api.py +0 -23
  227. gw_certificate/api_if/200/data.json +0 -106
  228. gw_certificate/api_if/200/status.json +0 -47
  229. gw_certificate/api_if/201/data.json +0 -98
  230. gw_certificate/api_if/201/status.json +0 -53
  231. gw_certificate/api_if/205/logs.json +0 -12
  232. gw_certificate/api_if/api_validation.py +0 -38
  233. gw_certificate/api_if/gw_capabilities.py +0 -54
  234. gw_certificate/cert_results.py +0 -145
  235. gw_certificate/common/analysis_data_bricks.py +0 -60
  236. gw_certificate/common/debug.py +0 -42
  237. gw_certificate/common/serialization_formatter.py +0 -93
  238. gw_certificate/common/utils.py +0 -8
  239. gw_certificate/common/utils_defines.py +0 -15
  240. gw_certificate/common/wltPb_pb2.py +0 -84
  241. gw_certificate/gw_certificate.py +0 -154
  242. gw_certificate/gw_certificate_cli.py +0 -87
  243. gw_certificate/interface/4.4.93_app.zip +0 -0
  244. gw_certificate/interface/4.4.93_sd_bl_app.zip +0 -0
  245. gw_certificate/interface/ble_simulator.py +0 -61
  246. gw_certificate/interface/ble_sniffer.py +0 -189
  247. gw_certificate/interface/flash_fw.py +0 -90
  248. gw_certificate/interface/if_defines.py +0 -36
  249. gw_certificate/interface/mqtt.py +0 -563
  250. gw_certificate/interface/nrfutil-linux +0 -0
  251. gw_certificate/interface/nrfutil-mac +0 -0
  252. gw_certificate/interface/nrfutil.exe +0 -0
  253. gw_certificate/interface/pkt_generator.py +0 -594
  254. gw_certificate/interface/uart_if.py +0 -236
  255. gw_certificate/interface/uart_ports.py +0 -20
  256. gw_certificate/templates/results.html +0 -241
  257. gw_certificate/templates/stage.html +0 -22
  258. gw_certificate/templates/table.html +0 -6
  259. gw_certificate/templates/test.html +0 -38
  260. gw_certificate/tests/__init__.py +0 -10
  261. gw_certificate/tests/actions.py +0 -289
  262. gw_certificate/tests/bad_crc_to_PER_quantization.csv +0 -51
  263. gw_certificate/tests/connection.py +0 -188
  264. gw_certificate/tests/downlink.py +0 -172
  265. gw_certificate/tests/generic.py +0 -238
  266. gw_certificate/tests/registration.py +0 -340
  267. gw_certificate/tests/static/__init__.py +0 -0
  268. gw_certificate/tests/static/connection_defines.py +0 -9
  269. gw_certificate/tests/static/downlink_defines.py +0 -9
  270. gw_certificate/tests/static/generated_packet_table.py +0 -195
  271. gw_certificate/tests/static/packet_table.csv +0 -10067
  272. gw_certificate/tests/static/references.py +0 -5
  273. gw_certificate/tests/static/uplink_defines.py +0 -14
  274. gw_certificate/tests/throughput.py +0 -240
  275. gw_certificate/tests/uplink.py +0 -853
  276. wiliot_certificate-4.4.3.dist-info/METADATA +0 -211
  277. wiliot_certificate-4.4.3.dist-info/RECORD +0 -210
  278. wiliot_certificate-4.4.3.dist-info/entry_points.txt +0 -3
  279. wiliot_certificate-4.4.3.dist-info/top_level.txt +0 -3
  280. {brg_certificate → certificate}/__init__.py +0 -0
  281. {brg_certificate → certificate}/ag/wlt_types_ag_jsons/side_info_sensor.json +0 -0
  282. {brg_certificate → certificate}/ag/wlt_types_ag_jsons/signal_indicator_data.json +0 -0
  283. {gw_certificate → common}/api_if/202/data.json +0 -0
  284. {gw_certificate/api_if/200 → common/api_if/202}/logs.json +0 -0
  285. {gw_certificate → common}/api_if/203/data.json +0 -0
  286. {gw_certificate/api_if/201 → common/api_if/203}/logs.json +0 -0
  287. {gw_certificate → common}/api_if/204/data.json +0 -0
  288. {gw_certificate/api_if/202 → common/api_if/204}/logs.json +0 -0
  289. {gw_certificate → common}/api_if/205/data.json +0 -0
  290. {gw_certificate/api_if/203 → common/api_if/205}/logs.json +0 -0
  291. {gw_certificate → common}/api_if/205/status.json +0 -0
  292. {gw_certificate/api_if/204 → common/api_if/206}/logs.json +0 -0
  293. {gw_certificate → common/api_if}/__init__.py +0 -0
  294. {gw_certificate/api_if → gui_certificate}/__init__.py +0 -0
  295. {wiliot_certificate-4.4.3.dist-info → wiliot_certificate-4.5.0a1.dist-info}/licenses/LICENSE +0 -0
@@ -1,853 +0,0 @@
1
- import os
2
- import time
3
- from typing import Literal
4
- import pandas as pd
5
- import plotly.express as px
6
- import tabulate
7
- import pkg_resources
8
-
9
- from gw_certificate.ag.ut_defines import PAYLOAD, LAT, LNG
10
- from gw_certificate.common.debug import debug_print
11
- from gw_certificate.api_if.gw_capabilities import GWCapabilities
12
- from gw_certificate.interface.ble_simulator import BLESimulator
13
- from gw_certificate.interface.if_defines import DEFAULT_DELAY, LOCATION
14
- from gw_certificate.tests.static.uplink_defines import *
15
- from gw_certificate.interface.mqtt import MqttClient, Serialization
16
- from gw_certificate.interface.pkt_generator import BrgPktGenerator, apply_adva_bitmask
17
- from gw_certificate.tests.static.generated_packet_table import UnifiedRunData, SensorRunData, MgmtRunData, PacketTableHelper, ACLRunData
18
- from gw_certificate.tests.generic import PassCriteria, PERFECT_SCORE, MINIMUM_SCORE, GenericTest, GenericStage, ERR_SUMMARY_DEFAULT, INFORMATIVE
19
- from gw_certificate.api_if.api_validation import MESSAGE_TYPES, validate_message
20
- from gw_certificate.tests.static.generated_packet_table import CSV_NAME
21
- from gw_certificate.common.serialization_formatter import ACL_MODE, ACL_BRIDGE_IDS, SerializationFormatter, Configurable, ACL_ALLOW, ACL_DENY
22
-
23
-
24
- # HELPER DEFINES
25
- TABLE_SUFFIX = "Table"
26
- ERR_SUM_MISSING_PKTS = "Insufficient amount of packets were scanned & uploaded by the gateway. "
27
- ERR_SUM_ONLY_1E = "Packets with length != '1E' were not uploaded. "
28
- ACL_MODE_COUNT = 2
29
-
30
- # HELPER FUNCTIONS
31
- def process_payload(packet:dict):
32
- payload = packet[PAYLOAD]
33
- payload = payload.upper()
34
- if len(payload) == 62 and payload[2:4] == '16':
35
- payload = payload [4:]
36
- # big2little endian
37
- if payload[:4] == 'FCC6':
38
- payload = 'C6FC' + payload[4:]
39
- packet[PAYLOAD] = payload
40
- return packet
41
-
42
- # HELPER CLASSES
43
- class TimestampsHelper(PacketTableHelper):
44
- def __init__(self):
45
- self.ts_errors = []
46
- self.has_out_of_range_ts = False
47
- self.has_identical_ts = False
48
- super().__init__()
49
-
50
- def set_adv_timestamp(self, data_payload, timestamp):
51
- self.set_field(data_payload, ADV_TIMESTAMP, timestamp)
52
-
53
- def set_adv_timestamp_current(self, data_payload):
54
- cur_ts = time.time_ns() // 1_000_000
55
- self.set_field(data_payload, ADV_TIMESTAMP, cur_ts)
56
-
57
- def get_adv_timestamp(self, data_payload):
58
- return self.get_field(data_payload, ADV_TIMESTAMP)
59
-
60
- def get_advertised_entries(self):
61
- """
62
- return the lines that contains a packets advertied already. These has the 'adv_timestamp' field.
63
- """
64
- return self.table.loc[self.table[ADV_TIMESTAMP].notna()]
65
-
66
- def validate_timestamps(self, received_pkts:list, has_si=False):
67
- packets_sent_df = self.get_advertised_entries().copy()
68
-
69
- received_df = pd.DataFrame(received_pkts)
70
- if PAYLOAD not in received_df.columns or TIMESTAMP not in received_df.columns:
71
- debug_print(f"Can't find payload/timestamp columns, skipping timestamp validation")
72
- return
73
- received_df = received_df[[PAYLOAD, TIMESTAMP]]
74
- received_df[TIMESTAMP] = pd.to_numeric(received_df[TIMESTAMP], errors='coerce')
75
-
76
- # Map payloads to their received timestamps
77
- payload_to_ts = received_df.groupby(PAYLOAD)[TIMESTAMP].first().to_dict()
78
-
79
- # Calculate adv_duration once
80
- def calculate_adv_duration(row):
81
- if pd.isna(row['duplication']) or pd.isna(row['time_delay']):
82
- return DEFAULT_DELAY
83
- elif has_si:
84
- return row['duplication'] * row['time_delay'] * 2
85
- else:
86
- return row['duplication'] * row['time_delay']
87
-
88
- packets_sent_df['adv_duration'] = packets_sent_df.apply(calculate_adv_duration, axis=1)
89
-
90
- # Validate timestamps using vectorized operations
91
- def validate_row(row):
92
- if row[PAYLOAD] in payload_to_ts:
93
- received_ts = payload_to_ts[row[PAYLOAD]]
94
- advertised_ts = row[ADV_TIMESTAMP]
95
- adv_duration = row['adv_duration']
96
-
97
- min_accepted_ts = int(advertised_ts - (adv_duration + TS_DEVIATION))
98
- max_accepted_ts = int(advertised_ts + TS_TOLERANCE + TS_DEVIATION)
99
-
100
- if not (min_accepted_ts < received_ts < max_accepted_ts):
101
- self.ts_errors.append(
102
- f"Timestamp {received_ts} is too far off the accepted range "
103
- f"{min_accepted_ts}-{max_accepted_ts} for payload: {row[PAYLOAD]}"
104
- )
105
- self.has_out_of_range_ts = True
106
- return received_ts
107
- return None
108
-
109
- packets_sent_df[REC_TIMESTAMP] = packets_sent_df.apply(validate_row, axis=1)
110
-
111
- # # Validate no 2 packets hold the same timestamp - disabled, not a requirement for certification
112
- # if REC_TIMESTAMP in packets_sent_df.columns:
113
- # duplicates = packets_sent_df[REC_TIMESTAMP].value_counts()
114
- # duplicated_ts = duplicates[duplicates > 1].index
115
-
116
- # for ts in duplicated_ts:
117
- # self.ts_errors.append(f"Multiple packets were uploaded with identical timestamp (ts = {int(ts)})")
118
- # self.has_identical_ts = True
119
-
120
- def add_ts_errs_to_report(self, stage:GenericStage, newline=True):
121
-
122
- for idx, ts_err in enumerate(self.ts_errors):
123
- stage.add_to_stage_report(ts_err)
124
- if idx == 1 and (len(self.ts_errors) - 1) > idx:
125
- stage.add_to_stage_report(f'Additional errors ({len(self.ts_errors) - 1 - idx}) are suppressed to avoid clutter')
126
- break
127
- if len(self.ts_errors) > 0 and newline:
128
- stage.add_to_stage_report('')
129
-
130
- def is_ts_error(self) -> bool:
131
- return len(self.ts_errors) > 0
132
-
133
-
134
- # TEST STAGES
135
- class GenericUplinkStage(GenericStage):
136
- def __init__(self, mqttc:MqttClient, ble_sim:BLESimulator, gw_capabilities:GWCapabilities, stage_name,
137
- **kwargs):
138
- self.__dict__.update(kwargs)
139
- super().__init__(stage_name=stage_name, **self.__dict__)
140
-
141
- # Clients
142
- self.mqttc = mqttc
143
- self.ble_sim = ble_sim
144
-
145
- # Packets list
146
- self.local_pkts = []
147
- self.mqtt_pkts = []
148
-
149
- # GW Capabilities
150
- self.gw_capabilities = gw_capabilities
151
-
152
- # Run data
153
- self.run_data = None
154
-
155
- self.ts_records = TimestampsHelper()
156
-
157
- def prepare_stage(self, reset_ble_sim=True):
158
- super().prepare_stage()
159
- self.mqttc.flush_messages()
160
- if reset_ble_sim:
161
- self.ble_sim.set_sim_mode(True)
162
-
163
- def fetch_mqtt_from_stage(self):
164
- mqtt_pkts = self.mqttc.get_all_tags_pkts()
165
- # self.mqtt_packets is a list of pkt jsons: [{timestamp:..., aliasbr.. payload...}, {...}]
166
- self.mqtt_pkts = list(map(lambda p: process_payload(p), mqtt_pkts))
167
-
168
- def compare_local_mqtt(self):
169
- self.fetch_mqtt_from_stage()
170
- local_pkts_df = pd.DataFrame(self.local_pkts, columns=[PAYLOAD, 'duplication', 'time_delay', 'aliasBridgeId'])
171
- mqtt_pkts_df = pd.DataFrame(self.mqtt_pkts)
172
- comparison = local_pkts_df
173
-
174
- if PAYLOAD not in mqtt_pkts_df.columns:
175
- mqtt_pkts_df[PAYLOAD] = ''
176
- received_pkts_df = pd.merge(local_pkts_df[PAYLOAD], mqtt_pkts_df[PAYLOAD], how='inner')
177
-
178
- received_pkts = set(received_pkts_df[PAYLOAD])
179
-
180
- self.pkts_received_count = pd.Series.count(received_pkts_df)
181
- unique_received_count = len(received_pkts)
182
- self.pkts_filtered_out_count = self.pkts_received_count - unique_received_count
183
-
184
- comparison[RECEIVED] = comparison[PAYLOAD].isin(received_pkts)
185
- comparison['pkt_id'] = comparison[PAYLOAD].apply(lambda x: x[-8:])
186
- self.comparison = comparison
187
-
188
- def generate_stage_report(self):
189
- """
190
- Generates report for the stage
191
- """
192
- self.compare_local_mqtt()
193
- self.ts_records.validate_timestamps(self.mqtt_pkts)
194
-
195
- num_pkts_sent = len(self.comparison)
196
- num_pkts_received = self.comparison['received'].eq(True).sum()
197
- self.stage_pass = num_pkts_received / num_pkts_sent * PERFECT_SCORE
198
- if self.stage_pass < self.pass_min:
199
- self.error_summary = ERR_SUM_MISSING_PKTS
200
-
201
- self.add_report_header()
202
- self.add_to_stage_report(f'Number of unique packets sent: {num_pkts_sent}')
203
- self.add_to_stage_report(f'Number of unique packets received: {num_pkts_received}')
204
- self.add_to_stage_report(f'Number of total packets received: {self.pkts_received_count}')
205
- self.add_to_stage_report(f'Number of duplicates out of total: {self.pkts_filtered_out_count}\n')
206
-
207
- not_received = self.comparison[self.comparison[RECEIVED]==False][REPORT_COLUMNS]
208
- if len(not_received) > 0:
209
- self.add_to_stage_report('Packets not received:')
210
- self.add_to_stage_report(tabulate.tabulate(not_received, headers='keys', showindex=False))
211
- self.add_to_stage_report('')
212
-
213
- self.ts_records.add_ts_errs_to_report(self)
214
-
215
- if num_pkts_received > 0:
216
- self.add_report_topic_validation('data')
217
-
218
- self.comparison.to_csv(self.csv_path)
219
- self.add_to_stage_report(f'Stage data saved - {self.csv_path}')
220
- debug_print(self.report)
221
-
222
- # Generate HTML
223
- table_html = self.template_engine.render_template('table.html', dataframe=self.comparison.to_html(table_id=self.stage_name + TABLE_SUFFIX),
224
- table_id=self.stage_name + TABLE_SUFFIX)
225
- self.report_html = self.template_engine.render_template('stage.html', stage=self,
226
- stage_report=self.report.split('\n'), table=table_html)
227
-
228
- return self.report
229
-
230
- def swap_endianness(self, hex_str: str) -> str:
231
- return ''.join(format(b, '02X') for b in bytes.fromhex(hex_str)[::-1])
232
-
233
-
234
- class ManagementPacketStage(GenericUplinkStage):
235
- def __init__(self, **kwargs):
236
- self.stage_tooltip = "Simulates management advertisements from a single bridge. Expects the gateway to scan & upload them"
237
- self.__dict__.update(kwargs)
238
- super().__init__(**self.__dict__, stage_name=type(self).__name__)
239
- self.run_data = MgmtRunData().data
240
- self.pass_min = 40
241
- self.inconclusive_min = 30
242
-
243
- def run(self):
244
- super().run()
245
- for index, row in self.run_data.iterrows():
246
- data = row[ADVA_PAYLOAD]
247
- self.local_pkts.append((row[PAYLOAD], row['duplication'], row['time_delay'], row['adva']))
248
- self.ble_sim.send_packet(raw_packet=data, duplicates=row['duplication'], delay=row['time_delay'])
249
- self.ts_records.set_adv_timestamp_current(data)
250
- time.sleep(10)
251
-
252
- def generate_stage_report(self):
253
- self.compare_local_mqtt()
254
- self.ts_records.validate_timestamps(self.mqtt_pkts)
255
-
256
- num_pkts_sent = len(self.comparison)
257
- num_pkts_received = self.comparison['received'].eq(True).sum()
258
- self.stage_pass = num_pkts_received / num_pkts_sent * PERFECT_SCORE
259
- if self.stage_pass < self.pass_min:
260
- self.error_summary = ERR_SUM_MISSING_PKTS
261
-
262
- self.add_report_header()
263
- self.add_to_stage_report(f'Number of unique packets sent: {num_pkts_sent}')
264
- self.add_to_stage_report(f'Number of unique packets received: {num_pkts_received}\n')
265
-
266
- not_received = self.comparison[self.comparison[RECEIVED]==False][REPORT_COLUMNS]
267
- if len(not_received) > 0:
268
- self.add_to_stage_report('Packets not received:')
269
- self.add_to_stage_report(tabulate.tabulate(not_received, headers='keys', showindex=False))
270
- self.add_to_stage_report('Check the CSV for more info')
271
-
272
- if num_pkts_received > 0:
273
- self.add_report_topic_validation('data')
274
-
275
- self.ts_records.add_ts_errs_to_report(self)
276
-
277
- self.comparison.to_csv(self.csv_path)
278
- self.add_to_stage_report(f'Stage data saved - {self.csv_path}')
279
- debug_print(self.report)
280
-
281
- # Generate HTML
282
- self.report_html = self.template_engine.render_template('stage.html', stage=self,
283
- stage_report=self.report.split('\n'))
284
-
285
- return self.report
286
-
287
- class DataPacketStage(GenericUplinkStage):
288
-
289
- def __init__(self, **kwargs):
290
- self.stage_tooltip = "Simulates advertisements from three bridges. Expects the gateway to scan & upload them"
291
- self.__dict__.update(kwargs)
292
- super().__init__(**self.__dict__, stage_name=type(self).__name__)
293
- self.run_data = UnifiedRunData().data
294
-
295
- def run(self):
296
- super().run()
297
- for index, row in self.run_data.iterrows():
298
- data = row[ADVA_PAYLOAD]
299
- # cur_ts = time.time_ns() // 1_000_000
300
- self.local_pkts.append((row[PAYLOAD], row['duplication'], row['time_delay'], row['adva']))
301
- self.ble_sim.send_packet(raw_packet=data, duplicates=row['duplication'], delay=row['time_delay'])
302
- self.ts_records.set_adv_timestamp_current(data)
303
- time.sleep(5)
304
-
305
-
306
- class SensorPacketStage(GenericUplinkStage):
307
- def __init__(self, **kwargs):
308
- self.__dict__.update(kwargs)
309
- super().__init__(**self.__dict__, stage_name=type(self).__name__)
310
- self.pkt_gen = BrgPktGenerator()
311
- self.stage_tooltip = "Simulates sensor packets advertisements. Expects the gateway to scan & upload them"
312
- self.error_summary = ERR_SUM_MISSING_PKTS
313
- self.varying_len_sensors_count = 0
314
-
315
- def run(self):
316
-
317
- def remove_pre_uuid(payload:str) -> str:
318
- return payload[16:]
319
-
320
- super().run()
321
- run_data = SensorRunData()
322
- run_data = run_data.data
323
- for index, row in run_data.iterrows():
324
- data = row[ADVA_PAYLOAD]
325
- si = row['si']
326
- # Save to local_pkts once for data and once for side info. Each with corresponding adva.
327
- self.local_pkts.append((row[ADVA_PAYLOAD], row[PAYLOAD], row['duplication'], row['time_delay'], apply_adva_bitmask(row['bridge_id'], 'random_static')))
328
- self.local_pkts.append((row['si'], remove_pre_uuid(row['si']), row['duplication'], row['time_delay'], row['adva']))
329
- self.ble_sim.send_data_si_pair(data_packet=data, si_packet=si, duplicates=row['duplication'], delay=row['time_delay'])
330
- self.ts_records.set_adv_timestamp_current(data)
331
- if row[ADVA_PAYLOAD][12:14] != '1E':
332
- self.varying_len_sensors_count += 1
333
- time.sleep(5)
334
-
335
- def compare_local_mqtt(self):
336
- self.fetch_mqtt_from_stage()
337
- # 'columns' must correspond to number of columns appended previously
338
- local_pkts_df = pd.DataFrame(self.local_pkts, columns=[ADVA_PAYLOAD, PAYLOAD, 'duplication', 'time_delay', 'aliasBridgeId'])
339
- mqtt_pkts_df = pd.DataFrame(self.mqtt_pkts)
340
- comparison = local_pkts_df
341
-
342
- if not set(SHARED_COLUMNS) <= set(mqtt_pkts_df.columns):
343
- missing_columns = list(set(SHARED_COLUMNS) - set(mqtt_pkts_df.columns))
344
- for missing_column in missing_columns:
345
- if missing_column in OBJECT_COLUMNS:
346
- mqtt_pkts_df[missing_column] = ''
347
- if missing_column in INT64_COLUMNS:
348
- mqtt_pkts_df[missing_column] = 0
349
- received_pkts_df = pd.merge(local_pkts_df[SHARED_COLUMNS], mqtt_pkts_df[SHARED_COLUMNS], how='inner')
350
-
351
- received_pkts = set(received_pkts_df[PAYLOAD])
352
-
353
- self.pkts_received_count = pd.Series.count(received_pkts_df)
354
- unique_received_count = len(received_pkts)
355
- self.pkts_filtered_out_count = self.pkts_received_count - unique_received_count
356
-
357
- comparison[RECEIVED] = comparison[PAYLOAD].isin(received_pkts)
358
- comparison['pkt_id'] = comparison['payload'].apply(lambda x: x[-8:])
359
- self.comparison = comparison
360
-
361
- def generate_stage_report(self):
362
- self.compare_local_mqtt()
363
- self.ts_records.validate_timestamps(self.mqtt_pkts, has_si=True)
364
- num_pkts_sent = len(self.comparison)
365
- num_pkts_received = self.comparison['received'].eq(True).sum()
366
- pkt_id_pairs = self.comparison.groupby('pkt_id').filter(lambda x: x['received'].all() and len(x) == 2)
367
- unique_pkt_ids = pkt_id_pairs['pkt_id'].unique()
368
- num_pairs = len(unique_pkt_ids)
369
-
370
- if num_pairs > 1:
371
- self.stage_pass = PERFECT_SCORE
372
- else:
373
- self.stage_pass = MINIMUM_SCORE
374
-
375
- self.add_report_header()
376
- self.add_to_stage_report((f'Number of sensor packets sent: {int(num_pkts_sent / 2)}'))
377
- self.add_to_stage_report((f'Number of sensor packets received correctly: {num_pairs}\n'))
378
-
379
- not_received = self.comparison[self.comparison[RECEIVED]==False]
380
- not_received_rep_cols = not_received[REPORT_COLUMNS]
381
- if len(not_received) > 0:
382
- self.add_to_stage_report('Packets not received:')
383
- self.add_to_stage_report(tabulate.tabulate(not_received_rep_cols, headers='keys', showindex=False))
384
- self.add_to_stage_report('')
385
-
386
- def all_varying_len_sensors_missed(not_received_df):
387
- not_uploaded_count = 0
388
- for index, line in not_received_df.iterrows():
389
- if line[ADVA_PAYLOAD][12:14] != '1E':
390
- not_uploaded_count += 1
391
- if not_uploaded_count == self.varying_len_sensors_count:
392
- return True
393
- else:
394
- return False
395
-
396
- if all_varying_len_sensors_missed(not_received):
397
- self.add_to_stage_report(f"Warning {ERR_SUM_ONLY_1E}")
398
- if not self.score_fail():
399
- self.stage_pass = MINIMUM_SCORE
400
- self.error_summary = ERR_SUM_ONLY_1E
401
- else:
402
- self.error_summary += ERR_SUM_ONLY_1E
403
-
404
- self.ts_records.add_ts_errs_to_report(self)
405
-
406
- if num_pkts_received > 0:
407
- self.add_report_topic_validation('data')
408
-
409
- self.comparison.to_csv(self.csv_path)
410
- self.add_to_stage_report(f'Stage data saved - {self.csv_path}')
411
- debug_print(self.report)
412
-
413
- # Generate HTML
414
- table_html = self.template_engine.render_template('table.html', dataframe=self.comparison.to_html(table_id=self.stage_name + TABLE_SUFFIX),
415
- table_id=self.stage_name + TABLE_SUFFIX)
416
- self.report_html = self.template_engine.render_template('stage.html', stage=self,
417
- stage_report=self.report.split('\n'), table=table_html)
418
-
419
- return self.report
420
-
421
-
422
- class ApiValidationStage(GenericUplinkStage):
423
- def __init__(self, **kwargs):
424
- self.stage_tooltip = "Validates the JSON structure of messages uploaded by the gateway in previous stages"
425
- self.__dict__.update(kwargs)
426
- super().__init__(**self.__dict__, stage_name=type(self).__name__)
427
-
428
- def prepare_stage(self):
429
- super().prepare_stage(reset_ble_sim=False)
430
- self.mqttc.flush_messages()
431
-
432
- def generate_stage_report(self, **kwargs):
433
- report = []
434
- all_validations = []
435
- self.stage_pass = PERFECT_SCORE
436
-
437
- # Set stage as FAIL if no messages were received:
438
- if len(self.all_messages_in_test) == 0:
439
- self.stage_pass = MINIMUM_SCORE
440
- self.error_summary = "No packets were received"
441
-
442
- for idx, message in enumerate(self.all_messages_in_test):
443
- message_body = message.body
444
- if len(message_body['packets']) == 0:
445
- continue
446
- validation = validate_message(MESSAGE_TYPES.DATA, message_body)
447
- errors = []
448
- for e in validation[1]:
449
- if e.message not in errors:
450
- errors.append(e.message)
451
- all_validations.append({'valid':validation[0], 'errors': errors, 'message': message_body,})
452
- if not validation[0]:
453
- if 'Validation Errors:' not in report:
454
- report.append('Validation Errors:')
455
- report.append(f'- Message (idx={idx}, json timestamp={message_body.get(TIMESTAMP)}) Errors:')
456
- for e in errors:
457
- report.append(e)
458
- self.stage_pass = MINIMUM_SCORE
459
- self.error_summary = "API (JSON strcture) is invalid"
460
-
461
- self.add_report_header()
462
- # Add all messages that failed to validate to report
463
- for line in report:
464
- self.add_to_stage_report(line)
465
- all_validations_df = pd.DataFrame(all_validations)
466
- all_validations_df.to_csv(self.csv_path)
467
- self.add_to_stage_report(f'Stage data saved - {self.csv_path}')
468
- debug_print(self.report)
469
-
470
- #Generate HTML
471
- table_html = self.template_engine.render_template('table.html', dataframe=all_validations_df.to_html(table_id=self.stage_name + TABLE_SUFFIX),
472
- table_id=self.stage_name + TABLE_SUFFIX)
473
- self.report_html = self.template_engine.render_template('stage.html', stage=self,
474
- stage_report=self.report.split('\n'))
475
- return self.report
476
-
477
- class SequentialSequenceIdStage(GenericUplinkStage):
478
- def __init__(self, **kwargs):
479
- self.__dict__.update(kwargs)
480
- self.stage_tooltip = "Validates expected sequenceId in all packets"
481
- super().__init__(**self.__dict__, stage_name=type(self).__name__)
482
-
483
- def prepare_stage(self):
484
- super().prepare_stage(reset_ble_sim=False)
485
- self.mqttc.flush_messages()
486
-
487
- def generate_stage_report(self, **kwargs):
488
- report = []
489
- self.stage_pass = PERFECT_SCORE
490
- required_sequenceId = None
491
- sequenceId_valid = True
492
-
493
- def is_sequenceId_incremental(idx, message):
494
- nonlocal required_sequenceId, sequenceId_valid
495
- packets = message['packets']
496
-
497
- # check that there is sequenceId in all packets
498
- packets_w_seqid = list(filter(lambda p: 'sequenceId' in p, packets))
499
- if len(packets_w_seqid) == 0:
500
- sequenceId_valid = False
501
- report.append(f'No sequenceId in message {idx}. Expected sequenceId in all packets')
502
- self.error_summary += 'No SequenceId in packets.'
503
- return False
504
-
505
- # initialize the required sequenceId
506
- if idx == 0:
507
- first_pkt = packets[0]
508
- required_sequenceId = first_pkt['sequenceId']
509
-
510
- # check that for every packet in message the sequenceId is incremental:
511
- for pkt in packets:
512
- pkt_sequenceId = pkt['sequenceId']
513
- if pkt_sequenceId != required_sequenceId:
514
- if sequenceId_valid == True:
515
- report.append(f'SequenceId is not incremental.')
516
- report.append(f'Received packet with sequenceId {pkt_sequenceId}, when the expected is {required_sequenceId}')
517
- self.stage_pass = MINIMUM_SCORE
518
- self.error_summary = self.error_summary + 'SequenceId is not incremental. '
519
- sequenceId_valid = False
520
- break
521
- required_sequenceId += 1
522
-
523
- # Set message type according to coupling, location
524
- for idx, message in enumerate(self.all_messages_in_test):
525
- message_body = message.body
526
- is_sequenceId_incremental(idx=idx, message=message_body)
527
-
528
- self.add_report_header()
529
- for line in report:
530
- self.add_to_stage_report(line)
531
- debug_print(self.report)
532
-
533
- #Generate HTML
534
- self.report_html = self.template_engine.render_template('stage.html', stage=self,
535
- stage_report=self.report.split('\n'))
536
- return self.report
537
-
538
- class AliasBridgeIDStage(GenericUplinkStage):
539
- def __init__(self, **kwargs):
540
- self.stage_tooltip = "Validates the uploaded aliasBridgeId is as expected per payload"
541
- # Data extracted from the test csv
542
- self.all_test_payloads = None
543
- self.alias_bridge_id_df = None
544
- self.__dict__.update(kwargs)
545
- super().__init__(**self.__dict__, stage_name=type(self).__name__)
546
-
547
- def prepare_stage(self):
548
- super().prepare_stage(reset_ble_sim=False)
549
- self.mqttc.flush_messages()
550
-
551
- def get_data_from_test_csv(self):
552
- relative_path = 'static/' + CSV_NAME
553
- csv_path = pkg_resources.resource_filename(__name__, relative_path)
554
- df = pd.read_csv(csv_path)
555
- uplink_tests_df = df[(df['test'] == 'unified') | (df['test'] == 'mgmt') | (df['test'] == 'sensor')].copy()
556
-
557
- # Store all test payloads
558
- all_payloads = uplink_tests_df[PAYLOAD]
559
- self.all_test_payloads = all_payloads.tolist()
560
-
561
- # Create data set for alias bridge verification
562
- self.alias_bridge_id_df = uplink_tests_df.copy()
563
-
564
- def generate_stage_report(self, **kwargs):
565
- report = []
566
- self.stage_pass = PERFECT_SCORE
567
- self.get_data_from_test_csv()
568
- aliasBridgeId_valid = True
569
-
570
- def filter_non_test_packets(message):
571
- packets = message['packets']
572
- filtered_pkts = []
573
- for pkt in packets:
574
- pkt = process_payload(pkt)
575
- payload = pkt['payload']
576
- if any(payload in test_payload for test_payload in self.all_test_payloads):
577
- filtered_pkts.append(pkt)
578
- message['packets'] = filtered_pkts
579
-
580
- def is_alias_bridge_id_valid(message):
581
- nonlocal aliasBridgeId_valid
582
- packets = message['packets']
583
-
584
- for pkt in packets:
585
- if 'aliasBridgeId' in pkt:
586
- pkt_payload = pkt['payload']
587
- pkt_alias_bridge_id = pkt['aliasBridgeId']
588
- validation_data = self.alias_bridge_id_df[self.alias_bridge_id_df['payload'].str.contains(pkt_payload, case=False)]
589
- if len(validation_data) != 1:
590
- debug_print(f"validation_data unexpected len:{len(validation_data)}, for payload:{pkt_payload}")
591
- return
592
- expected_bridge_id = validation_data.iloc[0]['adva']
593
- expected_bridge_ids = [expected_bridge_id, self.swap_endianness(expected_bridge_id)]
594
- if pkt_alias_bridge_id.upper() not in expected_bridge_ids:
595
- report.append(f"Alias bridge ID of the packet does not match. Expected alias bridge IDs:{expected_bridge_ids} but the packet alias bridge ID is {pkt_alias_bridge_id}")
596
- self.stage_pass = MINIMUM_SCORE
597
- self.error_summary = "aliasBridgeId doesn't match the expected one of a packet. "
598
- aliasBridgeId_valid = False
599
-
600
- # Set stage as FAIL if no messages were received:
601
- if len(self.all_messages_in_test) == 0:
602
- self.stage_pass = MINIMUM_SCORE
603
- self.error_summary = "No packets were received"
604
-
605
- # Set message type according to coupling, location
606
- for idx, message in enumerate(self.all_messages_in_test):
607
- message_body = message.body
608
- filter_non_test_packets(message_body)
609
- if len(message_body['packets']) == 0:
610
- continue
611
- is_alias_bridge_id_valid(message=message_body)
612
-
613
- self.add_report_header()
614
- self.add_to_stage_report(f"{'---Alias bridge ID is valid' if aliasBridgeId_valid else '---Alias bridge ID is NOT valid'}")
615
- for line in report:
616
- self.add_to_stage_report(line)
617
- # Add all messages that failed to validate to report
618
- debug_print(self.report)
619
-
620
- #Generate HTML
621
- self.report_html = self.template_engine.render_template('stage.html', stage=self,
622
- stage_report=self.report.split('\n'))
623
- return self.report
624
-
625
-
626
-
627
- class GeolocationStage(GenericUplinkStage):
628
- def __init__(self, **kwargs):
629
- self.stage_tooltip = "Checks if lat/lng were uploaded under 'location' (optional JSON key) in the uploaded data messages"
630
- self.__dict__.update(kwargs)
631
- super().__init__(**self.__dict__, stage_name=type(self).__name__)
632
- self.graph_html_path = os.path.join(self.test_dir, f'{self.stage_name}.html')
633
- self.result_indication = INFORMATIVE
634
-
635
-
636
- def prepare_stage(self):
637
- super().prepare_stage(reset_ble_sim=False)
638
- self.mqttc.flush_messages()
639
-
640
- def generate_stage_report(self, **kwargs):
641
- locations_list = []
642
- locations_df = pd.DataFrame()
643
- self.stage_pass = MINIMUM_SCORE
644
- self.error_summary = "No coordinates were uploaded. "
645
-
646
- # Set message type according to coupling, location
647
- for message in self.all_messages_in_test:
648
- message = message.body
649
- timestamp = message[TIMESTAMP]
650
- if LOCATION in message.keys():
651
- loc = message[LOCATION]
652
- loc.update({TIMESTAMP:timestamp})
653
- locations_list.append(loc)
654
- num_unique_locs = 0
655
- if len(locations_list) > 0:
656
- self.stage_pass = PERFECT_SCORE
657
- self.error_summary = ''
658
- locations_df = pd.DataFrame(locations_list)
659
- num_unique_locs = locations_df[['lat', 'lng']].drop_duplicates().shape[0]
660
- fig = px.scatter_mapbox(locations_df, lat=LAT, lon=LNG, color='timestamp', zoom=10)
661
- fig.update(layout_coloraxis_showscale=False)
662
- fig.update_layout(scattermode="group", scattergap=0.95, mapbox_style="open-street-map")
663
-
664
- self.add_report_header()
665
- self.add_to_stage_report(f'Number of unique locations received: {num_unique_locs}')
666
- # Export all stage data
667
- locations_df.to_csv(self.csv_path)
668
- self.add_to_stage_report(f'\nStage data saved - {self.csv_path}')
669
- if num_unique_locs > 0:
670
- fig.write_html(self.graph_html_path)
671
- debug_print(self.report)
672
-
673
- #Generate HTML
674
- graph_div = fig.to_html(full_html=False, include_plotlyjs='cdn') if num_unique_locs > 0 else "No graph to display"
675
- self.report_html = self.template_engine.render_template('stage.html', stage=self,
676
- stage_report=self.report.split('\n'), graph = graph_div)
677
- return self.report
678
-
679
- class ACLStage(GenericUplinkStage):
680
- def __init__(self, **kwargs):
681
- self.stage_tooltip = "Configures the gateway's Access Control List and simulate bridges. Expects 100% discard rate"
682
- self.__dict__.update(kwargs)
683
- super().__init__(**self.__dict__, stage_name=type(self).__name__)
684
- self.pass_min = 60
685
- self.inconclusive_min = 50
686
- self.run_data = ACLRunData().data
687
-
688
- @property
689
- def acl_modes(self):
690
- return [ACL_ALLOW, ACL_DENY]
691
-
692
- def run(self):
693
- super().run()
694
-
695
- def advertise_packets(pkts_group, adv_count, acl_brg_ids, mode):
696
- acl_dict = {ACL_MODE: mode, ACL_BRIDGE_IDS: acl_brg_ids}
697
-
698
- # Calculate row indices we want to advertise
699
- df_packets_count = len(self.run_data) // adv_count
700
- start_idx = df_packets_count * pkts_group
701
- end_idx = df_packets_count * (pkts_group + 1)
702
-
703
- for index, row in self.run_data.iloc[start_idx:end_idx].iterrows():
704
- if mode == ACL_ALLOW:
705
- should_be_received = row['bridge_id'] in acl_brg_ids
706
- else:
707
- should_be_received = row['bridge_id'] not in acl_brg_ids
708
- data = row[ADVA_PAYLOAD]
709
- self.local_pkts.append((row[PAYLOAD], row['duplication'], row['time_delay'], row['adva'], acl_dict, should_be_received))
710
- self.ble_sim.send_packet(raw_packet=data, duplicates=row['duplication'], delay=row['time_delay'])
711
- self.ts_records.set_adv_timestamp_current(data)
712
-
713
- def configure_acl(mode, bridgeIds):
714
- acl_dict = {ACL_MODE: mode, ACL_BRIDGE_IDS: bridgeIds}
715
- ser_format = SerializationFormatter(self.mqttc.get_serialization())
716
- payload = ser_format.cfg_param_set(self.cfg_data.status_msg_get(), Configurable.ACL.value, acl_dict)
717
- self.mqttc.flush_messages_topic('status')
718
- self.mqttc.send_payload(payload)
719
- time.sleep(5 if self.aggregation_time == 0 else self.aggregation_time)
720
- debug_print('Status message received from gw:')
721
- gw_status = self.mqttc.get_status_message()
722
- if gw_status != None and isinstance(gw_status, dict) and ser_format.is_pb():
723
- gw_status = ser_format.pb_status_acl_bytes_to_hex_string(gw_status)
724
- debug_print(gw_status)
725
-
726
- # Configuring each bridge in ACL, once for each mode
727
- brg_ids = self.run_data['bridge_id'].unique().tolist()
728
- cfg_and_adv_loops = len(brg_ids) * len(self.acl_modes)
729
- i = 0
730
- for brg_id in brg_ids:
731
- acl_brg_ids = [brg_id]
732
- for mode in self.acl_modes:
733
- configure_acl(mode, acl_brg_ids)
734
- time.sleep(5 if self.aggregation_time == 0 else self.aggregation_time)
735
- advertise_packets(i, cfg_and_adv_loops, acl_brg_ids, mode)
736
- time.sleep(5 if self.aggregation_time == 0 else self.aggregation_time)
737
- i += 1
738
-
739
- configure_acl(ACL_DENY, [])
740
- time.sleep(5)
741
-
742
- def compare_local_mqtt(self):
743
- self.fetch_mqtt_from_stage()
744
- local_pkts_df = pd.DataFrame(self.local_pkts, columns=[PAYLOAD, 'duplication', 'time_delay', 'aliasBridgeId', 'ACL', SHOULD_RECEIVE])
745
- mqtt_pkts_df = pd.DataFrame(self.mqtt_pkts)
746
- comparison = local_pkts_df
747
-
748
- if PAYLOAD not in mqtt_pkts_df.columns:
749
- mqtt_pkts_df[PAYLOAD] = ''
750
- received_pkts_df = pd.merge(local_pkts_df[PAYLOAD], mqtt_pkts_df[PAYLOAD], how='inner')
751
-
752
- received_pkts = set(received_pkts_df[PAYLOAD])
753
-
754
- self.pkts_received_count = pd.Series.count(received_pkts_df)
755
- unique_received_count = len(received_pkts)
756
- self.pkts_filtered_out_count = self.pkts_received_count - unique_received_count
757
-
758
- comparison[RECEIVED] = comparison[PAYLOAD].isin(received_pkts)
759
- self.comparison = comparison
760
-
761
- def generate_stage_report(self):
762
- self.compare_local_mqtt()
763
- self.ts_records.validate_timestamps(self.mqtt_pkts)
764
- self.add_report_header()
765
-
766
- num_pkts_sent = len(self.comparison)
767
- num_pkts_received = self.comparison[RECEIVED].eq(True).sum()
768
- num_pkts_should_received = self.comparison[SHOULD_RECEIVE].eq(True).sum()
769
- num_pkts_should_discard = self.comparison[SHOULD_RECEIVE].eq(False).sum()
770
- num_pkts_discarded_correctly = (self.comparison[SHOULD_RECEIVE].eq(False) & self.comparison[RECEIVED].eq(False)).sum()
771
- num_pkts_received_correctly = (self.comparison[SHOULD_RECEIVE].eq(True) & self.comparison[RECEIVED].eq(True)).sum()
772
- num_pkts_failed_to_discard = (self.comparison[SHOULD_RECEIVE].eq(False) & self.comparison[RECEIVED].eq(True)).sum()
773
- num_pkts_failed_to_receive = (self.comparison[SHOULD_RECEIVE].eq(True) & self.comparison[RECEIVED].eq(False)).sum()
774
- self.add_to_stage_report(f"Total packets advertised: {num_pkts_sent}")
775
- self.add_to_stage_report(f"Packets received / should've received: {num_pkts_received_correctly} / {num_pkts_should_received}")
776
- self.add_to_stage_report(f"Packets discarded / should've discarded: {num_pkts_discarded_correctly} / {num_pkts_should_discard}")
777
- self.add_to_stage_report(f"Failed to discard: {num_pkts_failed_to_discard}\n")
778
-
779
- if num_pkts_failed_to_discard > 0:
780
- self.stage_pass = MINIMUM_SCORE
781
- self.error_summary = "Received packet/s that should've been discarded"
782
- for index, row in self.comparison.iterrows():
783
- if row[RECEIVED] == True and row[SHOULD_RECEIVE] == False:
784
- self.add_to_stage_report(f"Payload from bridge {row['aliasBridgeId']} should have been filtered out: {row[PAYLOAD]}")
785
- self.add_to_stage_report('')
786
- # Report packets failed to receive only if we have issue discarding.
787
- # Since it increase the likelyhood of bad logic, and not just missed packets
788
- if num_pkts_failed_to_receive > 0:
789
- for index, row in self.comparison.iterrows():
790
- if row[RECEIVED] == False and row[SHOULD_RECEIVE] == True:
791
- self.add_to_stage_report(f"Payload from bridge {row['aliasBridgeId']} wasn't received: {row[PAYLOAD]}")
792
- self.add_to_stage_report('')
793
- elif num_pkts_received == 0:
794
- self.stage_pass = MINIMUM_SCORE
795
- self.error_summary = "No packets received"
796
- debug_print(f"No packets were received")
797
- else:
798
- self.stage_pass = num_pkts_received / num_pkts_should_received * PERFECT_SCORE
799
- if self.stage_pass < self.pass_min:
800
- self.add_to_stage_report(ERR_SUM_MISSING_PKTS)
801
- self.error_summary = ERR_SUM_MISSING_PKTS
802
-
803
- if num_pkts_received > 0:
804
- self.add_report_topic_validation('data')
805
-
806
- self.ts_records.add_ts_errs_to_report(self)
807
-
808
- self.comparison.to_csv(self.csv_path)
809
- self.add_report_line_separator()
810
- self.add_to_stage_report(f'Stage data saved - {self.csv_path}')
811
- debug_print(self.report)
812
-
813
- # Generate HTML
814
- self.report_html = self.template_engine.render_template('stage.html', stage=self,
815
- stage_report=self.report.split('\n'))
816
-
817
- return self.report
818
-
819
- # TEST CLASS
820
- TX_STAGES = [ManagementPacketStage, DataPacketStage, SensorPacketStage, ACLStage]
821
- UNCOUPLED_STAGES = [ManagementPacketStage, DataPacketStage, SensorPacketStage,
822
- SequentialSequenceIdStage, GeolocationStage]
823
-
824
- class UplinkTest(GenericTest):
825
- def __init__(self, **kwargs):
826
- self.test_tooltip = "Stages related to gateway BLE scans & MQTT data uploads"
827
- self.__dict__.update(kwargs)
828
- super().__init__(**self.__dict__, test_name=type(self).__name__)
829
- self.all_messages_in_test = []
830
-
831
- def prepare_test(self):
832
- super().prepare_test()
833
- stages = UNCOUPLED_STAGES
834
- if self.mqttc.get_serialization() == Serialization.JSON:
835
- stages.append(ApiValidationStage)
836
- if self.cfg_data.is_acl_supported():
837
- stages.append(ACLStage)
838
- # if self.gw_capabilities.geoLocationSupport:
839
- # stages.append(GeolocationStage)
840
- self.stages = [stage(**self.__dict__) for stage in stages]
841
-
842
- def run(self):
843
- super().run()
844
- for stage in self.stages:
845
- stage.prepare_stage()
846
- stage.run()
847
- if self.aggregation_time != 0 and type(stage) in TX_STAGES:
848
- debug_print(f"Waiting {self.aggregation_time} seconds for packets to be uploaded before processing results..")
849
- time.sleep(self.aggregation_time)
850
- self.add_to_test_report(stage.generate_stage_report())
851
- self.test_pass = PassCriteria.calc_for_test(self, stage)
852
- self.all_messages_in_test.extend(self.mqttc.get_all_messages_from_topic('data'))
853
-