wiliot-certificate 4.4.2__py3-none-any.whl → 4.5.0__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.
- {brg_certificate → certificate}/ag/wlt_cmd_if.html +10 -4
- {brg_certificate → certificate}/ag/wlt_types_ag.py +1878 -519
- certificate/cert_common.py +1488 -0
- certificate/cert_config.py +480 -0
- {brg_certificate → certificate}/cert_data_sim.py +134 -46
- {brg_certificate → certificate}/cert_defines.py +129 -128
- {brg_certificate → certificate}/cert_gw_sim.py +183 -53
- {brg_certificate → certificate}/cert_mqtt.py +179 -64
- {brg_certificate → certificate}/cert_prints.py +35 -33
- {brg_certificate → certificate}/cert_protobuf.py +15 -6
- {brg_certificate → certificate}/cert_results.py +240 -64
- certificate/cert_utils.py +634 -0
- certificate/certificate.py +205 -0
- certificate/certificate_cli.py +76 -0
- certificate/certificate_eth_test_list.txt +76 -0
- certificate/certificate_sanity_test_list.txt +66 -0
- certificate/certificate_test_list.txt +76 -0
- {brg_certificate → certificate}/tests/calibration/interval_test/interval_test.json +3 -2
- {brg_certificate → certificate}/tests/calibration/interval_test/interval_test.py +7 -6
- certificate/tests/calibration/output_power_test/output_power_test.json +23 -0
- certificate/tests/calibration/output_power_test/output_power_test.py +39 -0
- {brg_certificate → certificate}/tests/calibration/pattern_test/pattern_test.json +2 -1
- {brg_certificate → certificate}/tests/calibration/pattern_test/pattern_test.py +20 -15
- certificate/tests/cloud_connectivity/acl_ext_adv_test/acl_ext_adv_test.json +15 -0
- certificate/tests/cloud_connectivity/acl_ext_adv_test/acl_ext_adv_test.py +140 -0
- certificate/tests/cloud_connectivity/acl_test/acl_test.json +15 -0
- certificate/tests/cloud_connectivity/acl_test/acl_test.py +96 -0
- certificate/tests/cloud_connectivity/brg_ota_test/brg_ota_test.json +19 -0
- certificate/tests/cloud_connectivity/brg_ota_test/brg_ota_test.py +41 -0
- certificate/tests/cloud_connectivity/channel_scan_behaviour_test/channel_scan_behaviour_test.json +19 -0
- certificate/tests/cloud_connectivity/channel_scan_behaviour_test/channel_scan_behaviour_test.py +215 -0
- certificate/tests/cloud_connectivity/connection_test/connection_test.json +18 -0
- certificate/tests/cloud_connectivity/connection_test/connection_test.py +67 -0
- certificate/tests/cloud_connectivity/deduplication_test/deduplication_test.json +15 -0
- certificate/tests/cloud_connectivity/deduplication_test/deduplication_test.py +80 -0
- certificate/tests/cloud_connectivity/downlink_test/downlink_test.json +21 -0
- certificate/tests/cloud_connectivity/downlink_test/downlink_test.py +201 -0
- certificate/tests/cloud_connectivity/ext_adv_stress_test/ext_adv_stress_test.json +17 -0
- certificate/tests/cloud_connectivity/ext_adv_stress_test/ext_adv_stress_test.py +104 -0
- certificate/tests/cloud_connectivity/reboot_test/reboot_test.json +18 -0
- certificate/tests/cloud_connectivity/reboot_test/reboot_test.py +59 -0
- certificate/tests/cloud_connectivity/registration_test/registration_test.json +20 -0
- certificate/tests/cloud_connectivity/registration_test/registration_test.py +384 -0
- certificate/tests/cloud_connectivity/registration_test/registration_test_cli.py +90 -0
- certificate/tests/cloud_connectivity/stress_test/stress_test.json +17 -0
- certificate/tests/cloud_connectivity/stress_test/stress_test.py +101 -0
- certificate/tests/cloud_connectivity/uplink_ext_adv_test/uplink_ext_adv_test.json +25 -0
- certificate/tests/cloud_connectivity/uplink_ext_adv_test/uplink_ext_adv_test.py +92 -0
- certificate/tests/cloud_connectivity/uplink_test/uplink_test.json +20 -0
- certificate/tests/cloud_connectivity/uplink_test/uplink_test.py +169 -0
- {brg_certificate → certificate}/tests/datapath/aging_test/aging_test.json +2 -1
- certificate/tests/datapath/aging_test/aging_test.py +142 -0
- certificate/tests/datapath/event_ble5_test/event_ble5_test.json +17 -0
- certificate/tests/datapath/event_ble5_test/event_ble5_test.py +89 -0
- certificate/tests/datapath/event_test/event_test.json +17 -0
- certificate/tests/datapath/event_test/event_test.py +80 -0
- {brg_certificate → certificate}/tests/datapath/num_of_tags_test/num_of_tags_test.json +4 -3
- {brg_certificate → certificate}/tests/datapath/num_of_tags_test/num_of_tags_test.py +19 -13
- certificate/tests/datapath/output_power_test/output_power_test.json +23 -0
- {brg_certificate → certificate}/tests/datapath/output_power_test/output_power_test.py +17 -6
- {brg_certificate → certificate}/tests/datapath/pacer_interval_ble5_test/pacer_interval_ble5_test.json +2 -1
- {brg_certificate → certificate}/tests/datapath/pacer_interval_ble5_test/pacer_interval_ble5_test.py +13 -11
- {brg_certificate → certificate}/tests/datapath/pacer_interval_test/pacer_interval_test.json +2 -1
- {brg_certificate → certificate}/tests/datapath/pacer_interval_test/pacer_interval_test.py +9 -7
- {brg_certificate → certificate}/tests/datapath/pattern_test/pattern_test.json +3 -2
- {brg_certificate → certificate}/tests/datapath/pattern_test/pattern_test.py +18 -6
- certificate/tests/datapath/pkt_filter_ble5_chl21_test/pkt_filter_ble5_chl21_test.json +20 -0
- certificate/tests/datapath/pkt_filter_ble5_chl21_test/pkt_filter_ble5_chl21_test.py +61 -0
- {brg_certificate → certificate}/tests/datapath/pkt_filter_ble5_test/pkt_filter_ble5_test.json +2 -1
- {brg_certificate → certificate}/tests/datapath/pkt_filter_ble5_test/pkt_filter_ble5_test.py +15 -14
- certificate/tests/datapath/pkt_filter_brg2gw_ext_adv_test/pkt_filter_brg2gw_ext_adv_test.json +19 -0
- certificate/tests/datapath/pkt_filter_brg2gw_ext_adv_test/pkt_filter_brg2gw_ext_adv_test.py +85 -0
- {brg_certificate → certificate}/tests/datapath/pkt_filter_gen3_test/pkt_filter_gen3_test.json +2 -1
- {brg_certificate → certificate}/tests/datapath/pkt_filter_gen3_test/pkt_filter_gen3_test.py +10 -9
- {brg_certificate → certificate}/tests/datapath/pkt_filter_test/pkt_filter_test.json +2 -1
- {brg_certificate → certificate}/tests/datapath/pkt_filter_test/pkt_filter_test.py +10 -9
- {brg_certificate → certificate}/tests/datapath/rssi_threshold_test/rssi_threshold_test.json +3 -2
- {brg_certificate → certificate}/tests/datapath/rssi_threshold_test/rssi_threshold_test.py +9 -8
- brg_certificate/tests/datapath/output_power_test/output_power_test.json → certificate/tests/datapath/rx_channel_hopping_test/rx_channel_hopping_test.json +6 -4
- certificate/tests/datapath/rx_channel_hopping_test/rx_channel_hopping_test.py +77 -0
- {brg_certificate → certificate}/tests/datapath/rx_channel_test/rx_channel_test.json +3 -2
- {brg_certificate → certificate}/tests/datapath/rx_channel_test/rx_channel_test.py +7 -6
- {brg_certificate → certificate}/tests/datapath/rx_rate_gen2_test/rx_rate_gen2_test.json +8 -7
- {brg_certificate → certificate}/tests/datapath/rx_rate_gen2_test/rx_rate_gen2_test.py +113 -73
- {brg_certificate → certificate}/tests/datapath/rx_rate_gen3_test/rx_rate_gen3_test.json +8 -7
- {brg_certificate → certificate}/tests/datapath/rx_rate_gen3_test/rx_rate_gen3_test.py +112 -72
- {brg_certificate → certificate}/tests/datapath/stress_gen3_test/stress_gen3_test.json +4 -3
- {brg_certificate → certificate}/tests/datapath/stress_gen3_test/stress_gen3_test.py +15 -11
- {brg_certificate → certificate}/tests/datapath/stress_test/stress_test.json +4 -3
- {brg_certificate → certificate}/tests/datapath/stress_test/stress_test.py +15 -11
- {brg_certificate → certificate}/tests/datapath/tx_repetition_test/tx_repetition_test.json +3 -1
- {brg_certificate → certificate}/tests/datapath/tx_repetition_test/tx_repetition_test.py +14 -13
- certificate/tests/edge_mgmt/action_blink_test/action_blink_test.json +15 -0
- certificate/tests/edge_mgmt/action_blink_test/action_blink_test.py +24 -0
- certificate/tests/edge_mgmt/action_get_battery_sensor_test/action_get_battery_sensor_test.json +15 -0
- certificate/tests/edge_mgmt/action_get_battery_sensor_test/action_get_battery_sensor_test.py +43 -0
- certificate/tests/edge_mgmt/action_get_module_test/action_get_module_test.json +15 -0
- certificate/tests/edge_mgmt/action_get_module_test/action_get_module_test.py +42 -0
- certificate/tests/edge_mgmt/action_get_pof_data_test/action_get_pof_data_test.json +15 -0
- certificate/tests/edge_mgmt/action_get_pof_data_test/action_get_pof_data_test.py +44 -0
- certificate/tests/edge_mgmt/action_gw_hb_test/action_gw_hb_test.json +16 -0
- certificate/tests/edge_mgmt/action_gw_hb_test/action_gw_hb_test.py +42 -0
- certificate/tests/edge_mgmt/action_reboot_test/action_reboot_test.json +15 -0
- certificate/tests/edge_mgmt/action_reboot_test/action_reboot_test.py +49 -0
- certificate/tests/edge_mgmt/action_restore_defaults_test/action_restore_defaults_test.json +15 -0
- certificate/tests/edge_mgmt/action_restore_defaults_test/action_restore_defaults_test.py +102 -0
- certificate/tests/edge_mgmt/action_send_hb_test/action_send_hb_test.json +15 -0
- certificate/tests/edge_mgmt/action_send_hb_test/action_send_hb_test.py +45 -0
- {brg_certificate → certificate}/tests/edge_mgmt/periodic_msgs_test/periodic_msgs_test.json +3 -2
- {brg_certificate → certificate}/tests/edge_mgmt/periodic_msgs_test/periodic_msgs_test.py +22 -11
- {brg_certificate → certificate}/tests/energy2400/duty_cycle_test/duty_cycle_test.json +2 -1
- {brg_certificate → certificate}/tests/energy2400/duty_cycle_test/duty_cycle_test.py +7 -6
- certificate/tests/energy2400/output_power_test/output_power_test.json +23 -0
- {brg_certificate → certificate}/tests/energy2400/output_power_test/output_power_test.py +17 -6
- {brg_certificate → certificate}/tests/energy2400/pattern_test/pattern_test.json +2 -1
- {brg_certificate → certificate}/tests/energy2400/pattern_test/pattern_test.py +7 -6
- certificate/tests/energy2400/signal_indicator_ble5_test/signal_indicator_ble5_test.json +26 -0
- certificate/tests/energy2400/signal_indicator_ble5_test/signal_indicator_ble5_test.py +379 -0
- certificate/tests/energy2400/signal_indicator_ext_adv_test/signal_indicator_ext_adv_test.json +20 -0
- certificate/tests/energy2400/signal_indicator_ext_adv_test/signal_indicator_ext_adv_test.py +173 -0
- certificate/tests/energy2400/signal_indicator_test/signal_indicator_test.json +24 -0
- certificate/tests/energy2400/signal_indicator_test/signal_indicator_test.py +350 -0
- {brg_certificate → certificate}/tests/energy_sub1g/duty_cycle_test/duty_cycle_test.json +2 -1
- {brg_certificate → certificate}/tests/energy_sub1g/duty_cycle_test/duty_cycle_test.py +7 -6
- {brg_certificate → certificate}/tests/energy_sub1g/pattern_test/pattern_test.json +2 -1
- {brg_certificate → certificate}/tests/energy_sub1g/pattern_test/pattern_test.py +7 -6
- {brg_certificate → certificate}/tests/pwr_mgmt/pwr_mgmt_test/pwr_mgmt_test.json +2 -1
- {brg_certificate → certificate}/tests/pwr_mgmt/pwr_mgmt_test/pwr_mgmt_test.py +10 -10
- {brg_certificate → certificate}/tests/sensors/ext_sensor_test/ext_sensor_test.json +5 -4
- certificate/tests/sensors/ext_sensor_test/ext_sensor_test.py +450 -0
- certificate/wlt_types.py +122 -0
- {gw_certificate → common}/api_if/202/status.json +6 -0
- {gw_certificate → common}/api_if/203/status.json +6 -0
- {gw_certificate → common}/api_if/204/status.json +6 -0
- common/api_if/206/data.json +85 -0
- common/api_if/206/status.json +69 -0
- common/api_if/api_validation.py +91 -0
- common/web/templates/generator.html +210 -0
- common/web/templates/index.html +20 -0
- common/web/templates/menu.html +54 -0
- common/web/templates/parser.html +53 -0
- {brg_certificate/ag → common/web/templates}/wlt_types.html +1216 -191
- common/web/web_utils.py +399 -0
- {brg_certificate → common}/wltPb_pb2.py +14 -12
- {gw_certificate/common → common}/wltPb_pb2.pyi +16 -2
- gui_certificate/gui_certificate_cli.py +14 -0
- gui_certificate/server.py +1267 -0
- gui_certificate/templates/cert_run.html +1273 -0
- wiliot_certificate-4.5.0.dist-info/METADATA +99 -0
- wiliot_certificate-4.5.0.dist-info/RECORD +168 -0
- {wiliot_certificate-4.4.2.dist-info → wiliot_certificate-4.5.0.dist-info}/WHEEL +1 -1
- wiliot_certificate-4.5.0.dist-info/entry_points.txt +5 -0
- wiliot_certificate-4.5.0.dist-info/top_level.txt +3 -0
- brg_certificate/ag/energous_v0_defines.py +0 -925
- brg_certificate/ag/energous_v1_defines.py +0 -931
- brg_certificate/ag/energous_v2_defines.py +0 -925
- brg_certificate/ag/energous_v3_defines.py +0 -925
- brg_certificate/ag/energous_v4_defines.py +0 -925
- brg_certificate/ag/fanstel_lan_v0_defines.py +0 -925
- brg_certificate/ag/fanstel_lte_v0_defines.py +0 -925
- brg_certificate/ag/fanstel_wifi_v0_defines.py +0 -925
- brg_certificate/ag/minew_lte_v0_defines.py +0 -925
- brg_certificate/ag/wlt_types_ag_jsons/brg2brg_ota.json +0 -142
- brg_certificate/ag/wlt_types_ag_jsons/brg2gw_hb.json +0 -785
- brg_certificate/ag/wlt_types_ag_jsons/brg2gw_hb_sleep.json +0 -139
- brg_certificate/ag/wlt_types_ag_jsons/calibration.json +0 -394
- brg_certificate/ag/wlt_types_ag_jsons/custom.json +0 -515
- brg_certificate/ag/wlt_types_ag_jsons/datapath.json +0 -672
- brg_certificate/ag/wlt_types_ag_jsons/energy2400.json +0 -550
- brg_certificate/ag/wlt_types_ag_jsons/energySub1g.json +0 -595
- brg_certificate/ag/wlt_types_ag_jsons/externalSensor.json +0 -598
- brg_certificate/ag/wlt_types_ag_jsons/interface.json +0 -938
- brg_certificate/ag/wlt_types_ag_jsons/powerManagement.json +0 -1234
- brg_certificate/ag/wlt_types_ag_jsons/side_info_sensor.json +0 -105
- brg_certificate/ag/wlt_types_ag_jsons/signal_indicator_data.json +0 -77
- brg_certificate/ag/wlt_types_ag_jsons/unified_echo_ext_pkt.json +0 -61
- brg_certificate/ag/wlt_types_ag_jsons/unified_echo_pkt.json +0 -110
- brg_certificate/brg_certificate.py +0 -225
- brg_certificate/brg_certificate_cli.py +0 -63
- brg_certificate/cert_common.py +0 -923
- brg_certificate/cert_config.py +0 -402
- brg_certificate/cert_utils.py +0 -362
- brg_certificate/certificate_bcc_sanity_test_list.txt +0 -40
- brg_certificate/certificate_bcc_test_list.txt +0 -48
- brg_certificate/certificate_sanity_test_list.txt +0 -43
- brg_certificate/certificate_test_list.txt +0 -53
- brg_certificate/config/eclipse.json +0 -10
- brg_certificate/config/hivemq.json +0 -10
- brg_certificate/config/mosquitto.json +0 -10
- brg_certificate/config/mosquitto.md +0 -95
- brg_certificate/config/wiliot-dev.json +0 -10
- brg_certificate/restore_brg.py +0 -61
- brg_certificate/tests/calibration/output_power_test/output_power_test.json +0 -16
- brg_certificate/tests/calibration/output_power_test/output_power_test.py +0 -28
- brg_certificate/tests/datapath/aging_test/aging_test.py +0 -143
- brg_certificate/tests/datapath/pacer_interval_tags_count_test/pacer_interval_tags_count_test.json +0 -16
- brg_certificate/tests/datapath/pacer_interval_tags_count_test/pacer_interval_tags_count_test.py +0 -73
- brg_certificate/tests/datapath/tx_repetition_algo_test/tx_repetition_algo_test.json +0 -17
- brg_certificate/tests/datapath/tx_repetition_algo_test/tx_repetition_algo_test.py +0 -118
- brg_certificate/tests/edge_mgmt/actions_test/actions_test.json +0 -14
- brg_certificate/tests/edge_mgmt/actions_test/actions_test.py +0 -396
- brg_certificate/tests/edge_mgmt/brg2brg_ota_ble5_test/brg2brg_ota_ble5_test.json +0 -20
- brg_certificate/tests/edge_mgmt/brg2brg_ota_ble5_test/brg2brg_ota_ble5_test.py +0 -94
- brg_certificate/tests/edge_mgmt/brg2brg_ota_test/brg2brg_ota_test.json +0 -19
- brg_certificate/tests/edge_mgmt/brg2brg_ota_test/brg2brg_ota_test.py +0 -87
- brg_certificate/tests/edge_mgmt/leds_test/leds_test.json +0 -17
- brg_certificate/tests/edge_mgmt/leds_test/leds_test.py +0 -223
- brg_certificate/tests/edge_mgmt/ota_test/ota_test.json +0 -17
- brg_certificate/tests/edge_mgmt/ota_test/ota_test.py +0 -128
- brg_certificate/tests/energy2400/output_power_test/output_power_test.json +0 -16
- brg_certificate/tests/energy2400/signal_indicator_ble5_10_250k_test/signal_indicator_ble5_10_250k_test.json +0 -20
- brg_certificate/tests/energy2400/signal_indicator_ble5_10_250k_test/signal_indicator_ble5_10_250k_test.py +0 -321
- brg_certificate/tests/energy2400/signal_indicator_ble5_10_500k_test/signal_indicator_ble5_10_500k_test.json +0 -20
- brg_certificate/tests/energy2400/signal_indicator_ble5_10_500k_test/signal_indicator_ble5_10_500k_test.py +0 -321
- brg_certificate/tests/energy2400/signal_indicator_sub1g_2_4_test/signal_indicator_sub1g_2_4_test.json +0 -20
- brg_certificate/tests/energy2400/signal_indicator_sub1g_2_4_test/signal_indicator_sub1g_2_4_test.py +0 -141
- brg_certificate/tests/energy2400/signal_indicator_test/signal_indicator_test.json +0 -20
- brg_certificate/tests/energy2400/signal_indicator_test/signal_indicator_test.py +0 -276
- brg_certificate/tests/energy_sub1g/signal_indicator_functionality_test/signal_indicator_functionality_test.json +0 -20
- brg_certificate/tests/energy_sub1g/signal_indicator_functionality_test/signal_indicator_functionality_test.py +0 -390
- brg_certificate/tests/energy_sub1g/signal_indicator_test/signal_indicator_test.json +0 -16
- brg_certificate/tests/energy_sub1g/signal_indicator_test/signal_indicator_test.py +0 -28
- brg_certificate/tests/sensors/ext_sensor_test/ext_sensor_test.py +0 -305
- brg_certificate/wltPb_pb2.pyi +0 -234
- brg_certificate/wlt_types.py +0 -113
- gw_certificate/ag/ut_defines.py +0 -364
- gw_certificate/ag/wlt_types.py +0 -85
- gw_certificate/ag/wlt_types_ag.py +0 -5310
- gw_certificate/ag/wlt_types_data.py +0 -64
- gw_certificate/api/extended_api.py +0 -23
- gw_certificate/api_if/200/data.json +0 -106
- gw_certificate/api_if/200/status.json +0 -47
- gw_certificate/api_if/201/data.json +0 -98
- gw_certificate/api_if/201/status.json +0 -53
- gw_certificate/api_if/205/logs.json +0 -12
- gw_certificate/api_if/api_validation.py +0 -38
- gw_certificate/api_if/gw_capabilities.py +0 -54
- gw_certificate/cert_results.py +0 -145
- gw_certificate/common/analysis_data_bricks.py +0 -60
- gw_certificate/common/debug.py +0 -42
- gw_certificate/common/serialization_formatter.py +0 -93
- gw_certificate/common/utils.py +0 -8
- gw_certificate/common/utils_defines.py +0 -15
- gw_certificate/common/wltPb_pb2.py +0 -84
- gw_certificate/gw_certificate.py +0 -154
- gw_certificate/gw_certificate_cli.py +0 -87
- gw_certificate/interface/4.4.91_app.zip +0 -0
- gw_certificate/interface/4.4.91_sd_bl_app.zip +0 -0
- gw_certificate/interface/ble_simulator.py +0 -61
- gw_certificate/interface/ble_sniffer.py +0 -189
- gw_certificate/interface/flash_fw.py +0 -90
- gw_certificate/interface/if_defines.py +0 -36
- gw_certificate/interface/mqtt.py +0 -563
- gw_certificate/interface/nrfutil-linux +0 -0
- gw_certificate/interface/nrfutil-mac +0 -0
- gw_certificate/interface/nrfutil.exe +0 -0
- gw_certificate/interface/pkt_generator.py +0 -594
- gw_certificate/interface/uart_if.py +0 -236
- gw_certificate/interface/uart_ports.py +0 -20
- gw_certificate/templates/results.html +0 -241
- gw_certificate/templates/stage.html +0 -22
- gw_certificate/templates/table.html +0 -6
- gw_certificate/templates/test.html +0 -38
- gw_certificate/tests/__init__.py +0 -10
- gw_certificate/tests/actions.py +0 -289
- gw_certificate/tests/bad_crc_to_PER_quantization.csv +0 -51
- gw_certificate/tests/connection.py +0 -188
- gw_certificate/tests/downlink.py +0 -172
- gw_certificate/tests/generic.py +0 -238
- gw_certificate/tests/registration.py +0 -340
- gw_certificate/tests/static/__init__.py +0 -0
- gw_certificate/tests/static/connection_defines.py +0 -9
- gw_certificate/tests/static/downlink_defines.py +0 -9
- gw_certificate/tests/static/generated_packet_table.py +0 -195
- gw_certificate/tests/static/packet_table.csv +0 -10067
- gw_certificate/tests/static/references.py +0 -5
- gw_certificate/tests/static/uplink_defines.py +0 -14
- gw_certificate/tests/throughput.py +0 -240
- gw_certificate/tests/uplink.py +0 -853
- wiliot_certificate-4.4.2.dist-info/METADATA +0 -211
- wiliot_certificate-4.4.2.dist-info/RECORD +0 -210
- wiliot_certificate-4.4.2.dist-info/entry_points.txt +0 -3
- wiliot_certificate-4.4.2.dist-info/top_level.txt +0 -3
- {brg_certificate → certificate}/__init__.py +0 -0
- {gw_certificate → common}/api_if/202/data.json +0 -0
- {gw_certificate/api_if/200 → common/api_if/202}/logs.json +0 -0
- {gw_certificate → common}/api_if/203/data.json +0 -0
- {gw_certificate/api_if/201 → common/api_if/203}/logs.json +0 -0
- {gw_certificate → common}/api_if/204/data.json +0 -0
- {gw_certificate/api_if/202 → common/api_if/204}/logs.json +0 -0
- {gw_certificate → common}/api_if/205/data.json +0 -0
- {gw_certificate/api_if/203 → common/api_if/205}/logs.json +0 -0
- {gw_certificate → common}/api_if/205/status.json +0 -0
- {gw_certificate/api_if/204 → common/api_if/206}/logs.json +0 -0
- {gw_certificate → common/api_if}/__init__.py +0 -0
- {gw_certificate/api_if → gui_certificate}/__init__.py +0 -0
- {wiliot_certificate-4.4.2.dist-info → wiliot_certificate-4.5.0.dist-info}/licenses/LICENSE +0 -0
gw_certificate/tests/uplink.py
DELETED
|
@@ -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
|
-
|