wiliot-certificate 1.3.0a1__py3-none-any.whl → 1.4.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 (184) hide show
  1. brg_certificate/__init__.py +0 -0
  2. brg_certificate/ag/energous_v0_defines.py +925 -0
  3. brg_certificate/ag/energous_v1_defines.py +931 -0
  4. brg_certificate/ag/energous_v2_defines.py +925 -0
  5. brg_certificate/ag/energous_v3_defines.py +925 -0
  6. brg_certificate/ag/energous_v4_defines.py +925 -0
  7. brg_certificate/ag/fanstel_lan_v0_defines.py +925 -0
  8. brg_certificate/ag/fanstel_lte_v0_defines.py +925 -0
  9. brg_certificate/ag/fanstel_wifi_v0_defines.py +925 -0
  10. brg_certificate/ag/minew_lte_v0_defines.py +925 -0
  11. brg_certificate/ag/wlt_cmd_if.html +102 -0
  12. brg_certificate/ag/wlt_types.html +6114 -0
  13. brg_certificate/ag/wlt_types_ag.py +7840 -0
  14. brg_certificate/ag/wlt_types_ag_jsons/brg2brg_ota.json +142 -0
  15. brg_certificate/ag/wlt_types_ag_jsons/brg2gw_hb.json +785 -0
  16. brg_certificate/ag/wlt_types_ag_jsons/brg2gw_hb_sleep.json +139 -0
  17. brg_certificate/ag/wlt_types_ag_jsons/calibration.json +394 -0
  18. brg_certificate/ag/wlt_types_ag_jsons/custom.json +515 -0
  19. brg_certificate/ag/wlt_types_ag_jsons/datapath.json +672 -0
  20. brg_certificate/ag/wlt_types_ag_jsons/energy2400.json +550 -0
  21. brg_certificate/ag/wlt_types_ag_jsons/energySub1g.json +595 -0
  22. brg_certificate/ag/wlt_types_ag_jsons/externalSensor.json +598 -0
  23. brg_certificate/ag/wlt_types_ag_jsons/interface.json +938 -0
  24. brg_certificate/ag/wlt_types_ag_jsons/powerManagement.json +1234 -0
  25. brg_certificate/ag/wlt_types_ag_jsons/side_info_sensor.json +105 -0
  26. brg_certificate/ag/wlt_types_ag_jsons/signal_indicator_data.json +77 -0
  27. brg_certificate/ag/wlt_types_ag_jsons/unified_echo_ext_pkt.json +61 -0
  28. brg_certificate/ag/wlt_types_ag_jsons/unified_echo_pkt.json +110 -0
  29. brg_certificate/brg_certificate.py +191 -0
  30. brg_certificate/brg_certificate_cli.py +47 -0
  31. brg_certificate/cert_common.py +828 -0
  32. brg_certificate/cert_config.py +395 -0
  33. brg_certificate/cert_data_sim.py +188 -0
  34. brg_certificate/cert_defines.py +337 -0
  35. brg_certificate/cert_gw_sim.py +285 -0
  36. brg_certificate/cert_mqtt.py +373 -0
  37. brg_certificate/cert_prints.py +181 -0
  38. brg_certificate/cert_protobuf.py +88 -0
  39. brg_certificate/cert_results.py +300 -0
  40. brg_certificate/cert_utils.py +358 -0
  41. brg_certificate/certificate_sanity_test_list.txt +36 -0
  42. brg_certificate/certificate_test_list.txt +43 -0
  43. brg_certificate/config/eclipse.json +10 -0
  44. brg_certificate/config/hivemq.json +10 -0
  45. brg_certificate/config/mosquitto.json +10 -0
  46. brg_certificate/config/mosquitto.md +95 -0
  47. brg_certificate/config/wiliot-dev.json +10 -0
  48. brg_certificate/restore_brg.py +59 -0
  49. brg_certificate/tests/calibration/interval_test/interval_test.json +13 -0
  50. brg_certificate/tests/calibration/interval_test/interval_test.py +28 -0
  51. brg_certificate/tests/calibration/output_power_test/output_power_test.json +13 -0
  52. brg_certificate/tests/calibration/output_power_test/output_power_test.py +28 -0
  53. brg_certificate/tests/calibration/pattern_test/pattern_test.json +13 -0
  54. brg_certificate/tests/calibration/pattern_test/pattern_test.py +70 -0
  55. brg_certificate/tests/datapath/adaptive_pacer_algo_test/adaptive_pacer_algo_test.json +13 -0
  56. brg_certificate/tests/datapath/adaptive_pacer_algo_test/adaptive_pacer_algo_test.py +76 -0
  57. brg_certificate/tests/datapath/num_of_tags_test/num_of_tags_test.json +13 -0
  58. brg_certificate/tests/datapath/num_of_tags_test/num_of_tags_test.py +83 -0
  59. brg_certificate/tests/datapath/output_power_test/output_power_test.json +13 -0
  60. brg_certificate/tests/datapath/output_power_test/output_power_test.py +27 -0
  61. brg_certificate/tests/datapath/pacer_interval_ble5_test/pacer_interval_ble5_test.json +13 -0
  62. brg_certificate/tests/datapath/pacer_interval_ble5_test/pacer_interval_ble5_test.py +43 -0
  63. brg_certificate/tests/datapath/pacer_interval_tags_count_test/pacer_interval_tags_count_test.json +13 -0
  64. brg_certificate/tests/datapath/pacer_interval_tags_count_test/pacer_interval_tags_count_test.py +63 -0
  65. brg_certificate/tests/datapath/pacer_interval_test/pacer_interval_test.json +13 -0
  66. brg_certificate/tests/datapath/pacer_interval_test/pacer_interval_test.py +50 -0
  67. brg_certificate/tests/datapath/pattern_test/pattern_test.json +13 -0
  68. brg_certificate/tests/datapath/pattern_test/pattern_test.py +28 -0
  69. brg_certificate/tests/datapath/pkt_filter_ble5_test/pkt_filter_ble5_test.json +13 -0
  70. brg_certificate/tests/datapath/pkt_filter_ble5_test/pkt_filter_ble5_test.py +51 -0
  71. brg_certificate/tests/datapath/pkt_filter_gen3_test/pkt_filter_gen3_test.json +13 -0
  72. brg_certificate/tests/datapath/pkt_filter_gen3_test/pkt_filter_gen3_test.py +54 -0
  73. brg_certificate/tests/datapath/pkt_filter_test/pkt_filter_test.json +13 -0
  74. brg_certificate/tests/datapath/pkt_filter_test/pkt_filter_test.py +55 -0
  75. brg_certificate/tests/datapath/rssi_threshold_test/rssi_threshold_test.json +13 -0
  76. brg_certificate/tests/datapath/rssi_threshold_test/rssi_threshold_test.py +73 -0
  77. brg_certificate/tests/datapath/rx_channel_test/rx_channel_test.json +13 -0
  78. brg_certificate/tests/datapath/rx_channel_test/rx_channel_test.py +41 -0
  79. brg_certificate/tests/datapath/rx_rate_gen2_test/rx_rate_gen2_test.json +21 -0
  80. brg_certificate/tests/datapath/rx_rate_gen2_test/rx_rate_gen2_test.py +184 -0
  81. brg_certificate/tests/datapath/rx_rate_gen3_test/rx_rate_gen3_test.json +21 -0
  82. brg_certificate/tests/datapath/rx_rate_gen3_test/rx_rate_gen3_test.py +210 -0
  83. brg_certificate/tests/datapath/stress_gen3_test/stress_gen3_test.json +30 -0
  84. brg_certificate/tests/datapath/stress_gen3_test/stress_gen3_test.py +203 -0
  85. brg_certificate/tests/datapath/stress_test/stress_test.json +30 -0
  86. brg_certificate/tests/datapath/stress_test/stress_test.py +210 -0
  87. brg_certificate/tests/datapath/tx_repetition_algo_test/tx_repetition_algo_test.json +13 -0
  88. brg_certificate/tests/datapath/tx_repetition_algo_test/tx_repetition_algo_test.py +113 -0
  89. brg_certificate/tests/datapath/tx_repetition_test/tx_repetition_test.json +13 -0
  90. brg_certificate/tests/datapath/tx_repetition_test/tx_repetition_test.py +79 -0
  91. brg_certificate/tests/edge_mgmt/actions_test/actions_test.json +13 -0
  92. brg_certificate/tests/edge_mgmt/actions_test/actions_test.py +432 -0
  93. brg_certificate/tests/edge_mgmt/brg2brg_ota_ble5_test/brg2brg_ota_ble5_test.json +13 -0
  94. brg_certificate/tests/edge_mgmt/brg2brg_ota_ble5_test/brg2brg_ota_ble5_test.py +94 -0
  95. brg_certificate/tests/edge_mgmt/brg2brg_ota_test/brg2brg_ota_test.json +13 -0
  96. brg_certificate/tests/edge_mgmt/brg2brg_ota_test/brg2brg_ota_test.py +87 -0
  97. brg_certificate/tests/edge_mgmt/leds_test/leds_test.json +13 -0
  98. brg_certificate/tests/edge_mgmt/leds_test/leds_test.py +210 -0
  99. brg_certificate/tests/edge_mgmt/ota_test/ota_test.json +13 -0
  100. brg_certificate/tests/edge_mgmt/ota_test/ota_test.py +83 -0
  101. brg_certificate/tests/edge_mgmt/stat_test/stat_test.json +13 -0
  102. brg_certificate/tests/edge_mgmt/stat_test/stat_test.py +48 -0
  103. brg_certificate/tests/energy2400/duty_cycle_test/duty_cycle_test.json +13 -0
  104. brg_certificate/tests/energy2400/duty_cycle_test/duty_cycle_test.py +26 -0
  105. brg_certificate/tests/energy2400/output_power_test/output_power_test.json +13 -0
  106. brg_certificate/tests/energy2400/output_power_test/output_power_test.py +27 -0
  107. brg_certificate/tests/energy2400/pattern_test/pattern_test.json +13 -0
  108. brg_certificate/tests/energy2400/pattern_test/pattern_test.py +28 -0
  109. brg_certificate/tests/energy2400/signal_indicator_ble5_test/signal_indicator_ble5_test.json +13 -0
  110. brg_certificate/tests/energy2400/signal_indicator_ble5_test/signal_indicator_ble5_test.py +398 -0
  111. brg_certificate/tests/energy2400/signal_indicator_sub1g_2_4_test/signal_indicator_sub1g_2_4_test.json +13 -0
  112. brg_certificate/tests/energy2400/signal_indicator_sub1g_2_4_test/signal_indicator_sub1g_2_4_test.py +153 -0
  113. brg_certificate/tests/energy2400/signal_indicator_test/signal_indicator_test.json +13 -0
  114. brg_certificate/tests/energy2400/signal_indicator_test/signal_indicator_test.py +264 -0
  115. brg_certificate/tests/energy_sub1g/duty_cycle_test/duty_cycle_test.json +13 -0
  116. brg_certificate/tests/energy_sub1g/duty_cycle_test/duty_cycle_test.py +27 -0
  117. brg_certificate/tests/energy_sub1g/pattern_test/pattern_test.json +13 -0
  118. brg_certificate/tests/energy_sub1g/pattern_test/pattern_test.py +26 -0
  119. brg_certificate/tests/energy_sub1g/signal_indicator_functionality_test/signal_indicator_functionality_test.json +13 -0
  120. brg_certificate/tests/energy_sub1g/signal_indicator_functionality_test/signal_indicator_functionality_test.py +397 -0
  121. brg_certificate/tests/energy_sub1g/signal_indicator_test/signal_indicator_test.json +13 -0
  122. brg_certificate/tests/energy_sub1g/signal_indicator_test/signal_indicator_test.py +27 -0
  123. brg_certificate/wltPb_pb2.py +72 -0
  124. brg_certificate/wltPb_pb2.pyi +227 -0
  125. brg_certificate/wlt_types.py +114 -0
  126. gw_certificate/api/extended_api.py +7 -1531
  127. gw_certificate/api_if/200/data.json +106 -0
  128. gw_certificate/api_if/200/logs.json +12 -0
  129. gw_certificate/api_if/200/status.json +47 -0
  130. gw_certificate/api_if/201/data.json +98 -0
  131. gw_certificate/api_if/201/logs.json +12 -0
  132. gw_certificate/api_if/201/status.json +53 -0
  133. gw_certificate/api_if/202/data.json +83 -0
  134. gw_certificate/api_if/202/logs.json +12 -0
  135. gw_certificate/api_if/202/status.json +60 -0
  136. gw_certificate/api_if/203/data.json +85 -0
  137. gw_certificate/api_if/203/logs.json +12 -0
  138. gw_certificate/api_if/203/status.json +63 -0
  139. gw_certificate/api_if/204/data.json +85 -0
  140. gw_certificate/api_if/204/logs.json +12 -0
  141. gw_certificate/api_if/204/status.json +63 -0
  142. gw_certificate/api_if/205/data.json +85 -0
  143. gw_certificate/api_if/205/logs.json +12 -0
  144. gw_certificate/api_if/205/status.json +63 -0
  145. gw_certificate/api_if/api_validation.py +0 -2
  146. gw_certificate/common/analysis_data_bricks.py +18 -1413
  147. gw_certificate/common/debug.py +0 -21
  148. gw_certificate/common/utils.py +1 -212
  149. gw_certificate/common/utils_defines.py +0 -87
  150. gw_certificate/gw_certificate.py +9 -7
  151. gw_certificate/gw_certificate_cli.py +39 -23
  152. gw_certificate/interface/4.4.52_app.zip +0 -0
  153. gw_certificate/interface/4.4.52_sd_bl_app.zip +0 -0
  154. gw_certificate/interface/ble_simulator.py +0 -32
  155. gw_certificate/interface/if_defines.py +1 -0
  156. gw_certificate/interface/mqtt.py +96 -19
  157. gw_certificate/interface/nrfutil-linux +0 -0
  158. gw_certificate/interface/nrfutil-mac +0 -0
  159. gw_certificate/interface/nrfutil.exe +0 -0
  160. gw_certificate/interface/pkt_generator.py +0 -82
  161. gw_certificate/interface/uart_if.py +73 -43
  162. gw_certificate/templates/results.html +1 -1
  163. gw_certificate/tests/__init__.py +1 -2
  164. gw_certificate/tests/actions.py +134 -9
  165. gw_certificate/tests/connection.py +10 -5
  166. gw_certificate/tests/downlink.py +2 -4
  167. gw_certificate/tests/generic.py +62 -12
  168. gw_certificate/tests/registration.py +78 -27
  169. gw_certificate/tests/static/generated_packet_table.py +12 -48
  170. gw_certificate/tests/static/packet_table.csv +10048 -10048
  171. gw_certificate/tests/static/references.py +2 -1
  172. gw_certificate/tests/static/uplink_defines.py +0 -7
  173. gw_certificate/tests/throughput.py +7 -12
  174. gw_certificate/tests/uplink.py +83 -43
  175. {wiliot_certificate-1.3.0a1.dist-info → wiliot_certificate-1.4.0a1.dist-info}/METADATA +59 -8
  176. wiliot_certificate-1.4.0a1.dist-info/RECORD +198 -0
  177. {wiliot_certificate-1.3.0a1.dist-info → wiliot_certificate-1.4.0a1.dist-info}/WHEEL +1 -1
  178. wiliot_certificate-1.4.0a1.dist-info/entry_points.txt +3 -0
  179. wiliot_certificate-1.4.0a1.dist-info/top_level.txt +2 -0
  180. gw_certificate/interface/packet_error.py +0 -22
  181. wiliot_certificate-1.3.0a1.dist-info/RECORD +0 -51
  182. wiliot_certificate-1.3.0a1.dist-info/entry_points.txt +0 -2
  183. wiliot_certificate-1.3.0a1.dist-info/top_level.txt +0 -1
  184. {wiliot_certificate-1.3.0a1.dist-info → wiliot_certificate-1.4.0a1.dist-info}/LICENSE +0 -0
@@ -3,10 +3,17 @@ import os
3
3
  import time
4
4
  import pandas as pd
5
5
 
6
+ from packaging import version
7
+
6
8
  from gw_certificate.common.debug import debug_print
7
9
  from gw_certificate.interface.mqtt import MqttClient, GwAction
8
10
  from gw_certificate.tests.generic import PassCriteria, PERFECT_SCORE, MINIMUM_SCORE, INCONCLUSIVE_MINIMUM, GenericTest, GenericStage, OPTIONAL
9
- from gw_certificate.tests.static.references import GW_ACTIONS_DOC
11
+ from gw_certificate.tests.static.references import GW_ACTIONS_DOC, GW_BRIDGE_OTA_DOC
12
+ from gw_certificate.ag.ut_defines import STATUS_CODE_STR
13
+ from gw_certificate.interface.uart_if import FIRST_UNIFIED_BL_VERSION, UARTError
14
+
15
+
16
+ BL_INACTIVITY_TIMEOUT_SEC = 120
10
17
 
11
18
 
12
19
  class GenericActionsStage(GenericStage):
@@ -41,13 +48,21 @@ class GatewayInfoStage(GenericActionsStage):
41
48
 
42
49
  def run(self):
43
50
  super().run()
44
- self.gw_info = self.mqttc.get_gw_info()
51
+ timeout = datetime.datetime.now() + datetime.timedelta(seconds=20)
52
+ self.gw_info = None
53
+ self.mqttc.flush_messages()
54
+
55
+ self.mqttc.send_action(GwAction.GET_GW_INFO)
56
+ while datetime.datetime.now() < timeout and self.gw_info is None:
57
+ self.gw_info = self.mqttc.get_gw_info_message()
58
+ time.sleep(5)
59
+
45
60
 
46
61
  def generate_stage_report(self):
47
62
  super().generate_stage_report()
48
63
 
49
64
  # Calculate whether stage pass/failed
50
- if not self.gw_info or "gatewayInfo" not in self.gw_info.body or len(self.gw_info.body) > 1:
65
+ if self.gw_info == None:
51
66
  self.stage_pass = MINIMUM_SCORE
52
67
  self.add_to_stage_report(f'Did not receive a response to the Gateway Info action. For more info visit:')
53
68
  self.add_to_stage_report(f'{GW_ACTIONS_DOC}')
@@ -81,6 +96,7 @@ class RebootStage(GenericActionsStage):
81
96
  timeout = datetime.datetime.now() + datetime.timedelta(minutes=3)
82
97
  self.status_message = None
83
98
 
99
+ debug_print("Sending a reboot action to the gateway and awaiting reboot.. (timeout = 3)")
84
100
  self.mqttc.send_action(GwAction.REBOOT_GW)
85
101
  while datetime.datetime.now() < timeout and self.status_message is None:
86
102
  self.status_message = self.mqttc.get_status_message()
@@ -90,9 +106,7 @@ class RebootStage(GenericActionsStage):
90
106
  super().generate_stage_report()
91
107
 
92
108
  # Calculate whether stage pass/failed
93
- if (self.status_message is None or
94
- (not any('gatewayconf' == key.lower() for key in self.status_message.keys()) and
95
- not any('gatewaystatus' == key.lower() for key in self.status_message.keys()))):
109
+ if self.status_message is None:
96
110
  self.stage_pass = MINIMUM_SCORE
97
111
  self.add_to_stage_report(f"The gateway did not validly reboot")
98
112
  self.add_to_stage_report(f"Gateways are expected to upload a status(configuration) message upon establishing MQTT connection, which wasn't received.")
@@ -110,8 +124,113 @@ class RebootStage(GenericActionsStage):
110
124
  stage_report=self.report.split('\n'))
111
125
  return self.report
112
126
 
127
+ class BridgeOTAStage(GenericActionsStage):
128
+ def __init__(self, **kwargs):
129
+ super().__init__(**kwargs, stage_name=type(self).__name__)
130
+ self.stage_tooltip = "Issues a bridge OTA action to the gateway. Expects it to upgrade the bridge"
131
+ self.error_summary = "The target bridge was not upgraded"
132
+ self.action = "Bridge Upgrade"
133
+
134
+ OTA_VERSIONS_TO_USE = ("4.4.52", "4.4.53")
135
+ if version.parse(OTA_VERSIONS_TO_USE[0]) != self.uart.fw_version:
136
+ self.desired_version = version.parse(OTA_VERSIONS_TO_USE[0])
137
+ else:
138
+ self.desired_version = version.parse(OTA_VERSIONS_TO_USE[1])
139
+
140
+ def prepare_stage(self):
141
+ super().prepare_stage()
142
+ debug_print(f"Important: For the gateway to be able to download the file, it must use a valid token in the HTTP GET request.")
143
+ debug_print(f"Meaning It must be registered under an owner, and the certificate '-env' should correspond to that owner.")
144
+ debug_print(f"BridgeOTAStage attempt: {str(self.uart.fw_version)} -> {str(self.desired_version)}")
145
+ # Reset to remove any log/cert mode we had in the kit so it behaves as a bridge
146
+ self.uart.reset_gw()
147
+
148
+ def run(self):
149
+ super().run()
150
+ timeout = datetime.datetime.now() + datetime.timedelta(minutes=10)
151
+ self.action_status = None
152
+ self.status_code = None
153
+ self.reboot_packet_ts = None
154
+ self.action_status_ts = None
155
+
156
+ self.mqttc.send_bridge_ota_action(self.uart.mac, str(self.desired_version), 200, False, self.gw_id, "aws", self.env)
157
+ debug_print("Sent a BridgeOTA action to the gateway")
158
+ debug_print("Waiting for an actionStatus message from the gateway... (timeout=10)")
159
+ while datetime.datetime.now() < timeout and self.action_status is None:
160
+ line = self.uart.read_line()
161
+ if line != None and 'reset' in line:
162
+ self.uart.reset_gw(stop_advertising=False)
163
+ self.reboot_packet_ts = datetime.datetime.now()
164
+ debug_print("A reboot packet was received by the bridge")
165
+ self.action_status = self.mqttc.get_action_status_message()
166
+ time.sleep(2)
167
+
168
+ if self.action_status != None:
169
+ debug_print("actionStatus was received from the gateway")
170
+ self.action_status_ts = datetime.datetime.now()
171
+ self.status_code = self.action_status.get(STATUS_CODE_STR)
172
+ if self.status_code == None:
173
+ self.status_code = self.action_status.get('status')
174
+
175
+ if self.status_code != 0 and self.reboot_packet_ts != None:
176
+ debug_print(f"Reported status {self.status_code} indicates failure, waiting for the bridge bootloader inactivity timer (2 minutes)..")
177
+ time.sleep(BL_INACTIVITY_TIMEOUT_SEC)
178
+
179
+ debug_print('Waiting for the bridge to boot...')
180
+ time.sleep(40)
113
181
 
114
- STAGES = [GatewayInfoStage, RebootStage]
182
+ cur_ver = self.uart.get_version()
183
+ if cur_ver == None:
184
+ debug_print("ERROR: The certificate kit, acting as bridge in this stage, is not responding!")
185
+ self.uart.flush()
186
+ cur_ver = self.uart.get_version()
187
+ if cur_ver == None:
188
+ raise UARTError("Communication to the certificate kit halted! "
189
+ "Please unplug and replug its power source, wait for 5 minutes and retry. "
190
+ "If the error persist, contact Wiliot Support and attach your results directory.")
191
+ self.current_version = version.parse(cur_ver)
192
+
193
+ def generate_stage_report(self):
194
+ super().generate_stage_report()
195
+
196
+ # Calculate whether stage pass/failed
197
+ if self.action_status is None or self.status_code != 0:
198
+ self.stage_pass = MINIMUM_SCORE
199
+ self.add_to_stage_report(f"The bridge OTA test failed")
200
+ if self.action_status is None:
201
+ self.add_to_stage_report(f"Gateways are expected to upload an actionStatus message upon establishing MQTT connection, which wasn't received.")
202
+ elif self.status_code is None:
203
+ self.add_to_stage_report(f"Uploaded actionStatus messages should contain the status field, which wasn't detected.")
204
+ elif self.status_code != 0:
205
+ self.add_to_stage_report(f"Uploaded actionStatus status value received is {self.status_code}.")
206
+ if self.current_version == self.desired_version:
207
+ self.add_to_stage_report(f"Note that the bridge was actually upgraded successfully.")
208
+ self.add_to_stage_report(f"{GW_BRIDGE_OTA_DOC}")
209
+ else:
210
+ if self.current_version == self.desired_version:
211
+ self.stage_pass = PERFECT_SCORE
212
+ self.add_to_stage_report(f"Bridge was upgraded and an actionStatus message was received from the gateway.")
213
+ self.add_to_stage_report(f"Action status received {(self.action_status_ts - self.start_time).total_seconds():.1f}s after start.")
214
+ self.add_to_stage_report(f"Reboot packet received {(self.reboot_packet_ts - self.start_time).total_seconds():.1f}s after start.")
215
+ self.add_to_stage_report(f"Action status received {(self.action_status_ts - self.reboot_packet_ts).total_seconds():.1f}s after reboot.")
216
+ else:
217
+ self.stage_pass = MINIMUM_SCORE
218
+ self.add_to_stage_report(f"The bridge OTA test failed")
219
+ self.add_to_stage_report(f"Uploaded actionStatus message indicated success although the bridge was not upgraded.")
220
+
221
+ # Export all stage data
222
+ csv_data = {'Action': [self.action], 'Pass': [self.stage_pass > self.pass_min]}
223
+ if self.stage_pass == PERFECT_SCORE:
224
+ csv_data.update({'start_ts': self.start_time, 'reboot_packet_ts': self.reboot_packet_ts, 'action_status_ts': self.action_status_ts})
225
+ pd.DataFrame(csv_data).to_csv(self.summary_csv_path)
226
+ self.add_to_stage_report(f'\nStage summary saved - {self.summary_csv_path}')
227
+
228
+ # Generate HTML
229
+ self.report_html = self.template_engine.render_template('stage.html', stage=self,
230
+ stage_report=self.report.split('\n'))
231
+ return self.report
232
+
233
+ ACTIONS_STAGES = [GatewayInfoStage, RebootStage, BridgeOTAStage]
115
234
 
116
235
  class ActionsTest(GenericTest):
117
236
  def __init__(self, **kwargs):
@@ -119,7 +238,13 @@ class ActionsTest(GenericTest):
119
238
  super().__init__(**self.__dict__, test_name=type(self).__name__)
120
239
  self.test_tooltip = "Stages publishing different actions (via the 'update' topic). Optional"
121
240
  self.result_indication = OPTIONAL
122
- self.stages = [stage(**self.__dict__) for stage in STAGES]
241
+ # Actions stages are determined by the CLI argument
242
+ stages = self.actions
243
+
244
+ if BridgeOTAStage in stages and self.uart.fw_version < FIRST_UNIFIED_BL_VERSION:
245
+ debug_print("Certificate kit's firmware should be upgraded with the '-update' flag to run the BridgeOTAStage")
246
+ stages.remove(BridgeOTAStage)
247
+ self.stages = [stage(**self.__dict__) for stage in stages]
123
248
 
124
249
  def run(self):
125
250
  super().run()
@@ -128,4 +253,4 @@ class ActionsTest(GenericTest):
128
253
  stage.prepare_stage()
129
254
  stage.run()
130
255
  self.add_to_test_report(stage.generate_stage_report())
131
- self.test_pass = PassCriteria.calc_for_test(self.test_pass, stage)
256
+ self.test_pass = PassCriteria.calc_for_test(self, stage)
@@ -12,7 +12,9 @@ from gw_certificate.tests.generic import INCONCLUSIVE_MINIMUM, PassCriteria, MIN
12
12
  from gw_certificate.api_if.api_validation import validate_message, MESSAGE_TYPES
13
13
  from gw_certificate.interface.mqtt import MqttClient, Serialization
14
14
  from gw_certificate.interface.ble_sniffer import BLESniffer, BLESnifferContext
15
+ from gw_certificate.tests.static.references import GW_MQTT_DOC
15
16
 
17
+ STATUS_MSG_TIMEOUT = 5
16
18
 
17
19
  class ConnectionStage(GenericStage):
18
20
  def __init__(self, mqttc:MqttClient, **kwargs):
@@ -28,8 +30,8 @@ class ConnectionStage(GenericStage):
28
30
  'Please unplug GW from power. Press enter when unplugged')
29
31
  self.mqttc.flush_messages()
30
32
  input('Please plug GW back to power. Press enter when plugged')
31
- debug_print('Waiting for GW to connect... (Timeout 3 minutes)')
32
- timeout = datetime.datetime.now() + datetime.timedelta(minutes=3)
33
+ debug_print(f'Waiting for GW to connect... (Timeout {STATUS_MSG_TIMEOUT} minutes)')
34
+ timeout = datetime.datetime.now() + datetime.timedelta(minutes=STATUS_MSG_TIMEOUT)
33
35
  self.status_message = None
34
36
 
35
37
  while datetime.datetime.now() < timeout and self.status_message is None:
@@ -67,6 +69,9 @@ class ConnectionStage(GenericStage):
67
69
  self.add_to_stage_report(f'\n{len(self.validation[1])} validation errors:')
68
70
  for error in self.validation[1]:
69
71
  self.add_to_stage_report(error.message)
72
+ self.add_to_stage_report(f"Please look into the Status section in:\n{GW_MQTT_DOC}")
73
+
74
+ self.add_report_topic_validation('status')
70
75
  else:
71
76
  self.error_summary = "No message recieved from GW in status topic after 3 mins."
72
77
  self.add_to_stage_report(self.error_summary)
@@ -167,15 +172,15 @@ class ConnectionTest(GenericTest):
167
172
  self.__dict__.update(kwargs)
168
173
  super().__init__(**self.__dict__, test_name=type(self).__name__)
169
174
  stages = STAGES
170
- if version.parse(self.uart.get_version()) >= version.parse(INTERFERENCE_ANALYSIS_FW_VER):
175
+ current_version = self.uart.get_version()
176
+ if current_version != None and version.parse(current_version) >= version.parse(INTERFERENCE_ANALYSIS_FW_VER):
171
177
  stages.append(InterferenceAnalysisStage)
172
178
  self.stages = [stage(**self.__dict__) for stage in stages]
173
179
 
174
180
  def run(self):
175
181
  super().run()
176
- self.test_pass = PERFECT_SCORE
177
182
  for stage in self.stages:
178
183
  stage.prepare_stage()
179
184
  stage.run()
180
- self.test_pass = PassCriteria.calc_for_test(self.test_pass, stage)
185
+ self.test_pass = PassCriteria.calc_for_test(self, stage)
181
186
  self.add_to_test_report(stage.generate_stage_report())
@@ -4,7 +4,6 @@ import json
4
4
  import os
5
5
  import time
6
6
  import pandas as pd
7
- import numpy as np
8
7
  import plotly.express as px
9
8
  from google.protobuf.json_format import MessageToDict
10
9
 
@@ -99,7 +98,7 @@ class GenericDownlinkStage(GenericStage):
99
98
  self.error_summary = channel_err_summary
100
99
  self.add_to_stage_report(f"Channel {channel}: {PassCriteria.to_string(channel_pass)}")
101
100
  self.add_to_stage_report(f"- Total {len(channel_pkts['payload'])} MQTT payloads sent")
102
- self.add_to_stage_report(f"- Total {sum(channel_pkts['num_pkts_received'])} BLE Packets received by sniffer")
101
+ self.add_to_stage_report(f"- Total {sum(channel_pkts['num_pkts_received'])} BLE Packets received by sniffer (including duplicates)")
103
102
  self.add_to_stage_report(f"- R Value: {rsquared} | Slope: {slope}")
104
103
  # Export all stage data
105
104
  self.sent_pkts.to_csv(self.sent_csv_path)
@@ -166,9 +165,8 @@ class DownlinkTest(GenericTest):
166
165
 
167
166
  def run(self):
168
167
  super().run()
169
- self.test_pass = PERFECT_SCORE
170
168
  for stage in self.stages:
171
169
  stage.prepare_stage()
172
170
  stage.run()
173
171
  self.add_to_test_report(stage.generate_stage_report())
174
- self.test_pass = PassCriteria.calc_for_test(self.test_pass, stage)
172
+ self.test_pass = PassCriteria.calc_for_test(self, stage)
@@ -1,11 +1,11 @@
1
1
  import datetime
2
2
  import os
3
+ from typing import Literal
4
+ import math
3
5
 
4
- from gw_certificate.api.extended_api import ExtendedEdgeClient
5
6
  from gw_certificate.common.debug import debug_print
6
7
  from gw_certificate.api_if.gw_capabilities import GWCapabilities
7
8
  from gw_certificate.interface.ble_simulator import BLESimulator
8
- from gw_certificate.interface.if_defines import SEP
9
9
  from gw_certificate.interface.mqtt import MqttClient
10
10
 
11
11
  PASS_STATUS = {True: 'PASS', False: 'FAIL'}
@@ -23,6 +23,8 @@ SCORE_BASED = 'score'
23
23
  INFORMATIVE = 'info'
24
24
  OPTIONAL = 'optional'
25
25
 
26
+ ERR_SUMMARY_DEFAULT = 'View the stage report for more info. '
27
+
26
28
  class PassCriteria():
27
29
  def __init__(self):
28
30
  pass
@@ -53,7 +55,7 @@ class PassCriteria():
53
55
  def calc_for_stage_downlink(rsquared, slope, stage_name:str):
54
56
  error_msg = ''
55
57
  if 'Sanity' in stage_name:
56
- if rsquared > 0:
58
+ if not math.isnan(rsquared) and rsquared != 0:
57
59
  return PERFECT_SCORE, error_msg
58
60
  else:
59
61
  error_msg = 'No advertisements were received from the gateway.'
@@ -69,14 +71,17 @@ class PassCriteria():
69
71
  return MINIMUM_SCORE, error_msg
70
72
 
71
73
  @staticmethod
72
- def calc_for_test(test_pass_value:int, stage) -> int:
73
- if stage.stage_pass < test_pass_value:
74
- if 'Geolocation' in stage.stage_name or 'info' in stage.result_indication:
75
- return test_pass_value
76
- else:
77
- return stage.stage_pass
74
+ def calc_for_test(test, stage) -> int:
75
+ # Some stages shouldn't affect test score
76
+ if 'Geolocation' in stage.stage_name or 'info' in stage.result_indication:
77
+ return test.test_pass
78
+
79
+ if stage.score_inconclusive() and test.score_pass():
80
+ return test.inconclusive_min
81
+ elif stage.score_fail():
82
+ return MINIMUM_SCORE
78
83
  else:
79
- return test_pass_value
84
+ return test.test_pass
80
85
 
81
86
 
82
87
  class GenericTest:
@@ -90,7 +95,7 @@ class GenericTest:
90
95
  self.gw_capabilities = gw_capabilities
91
96
  self.report = ''
92
97
  self.report_html = ''
93
- self.test_pass = MINIMUM_SCORE
98
+ self.test_pass = PERFECT_SCORE
94
99
  self.pass_min = PASS_MINIMUM
95
100
  self.inconclusive_min = INCONCLUSIVE_MINIMUM
96
101
  self.start_time = None
@@ -104,6 +109,9 @@ class GenericTest:
104
109
  def __repr__(self):
105
110
  return self.test_name
106
111
 
112
+ def prepare_test(self):
113
+ pass
114
+
107
115
  def run(self):
108
116
  self.start_time = datetime.datetime.now()
109
117
  debug_print(f"Starting Test {self.test_name} : {self.start_time}")
@@ -121,6 +129,22 @@ class GenericTest:
121
129
  def end_test(self):
122
130
  self.create_test_html()
123
131
 
132
+ def score_pass(self):
133
+ if self.test_pass >= self.pass_min:
134
+ return True
135
+ return False
136
+
137
+ def score_inconclusive(self):
138
+ if self.inconclusive_min <= self.test_pass < self.pass_min:
139
+ return True
140
+ return False
141
+
142
+ def score_fail(self):
143
+ if self.test_pass < self.inconclusive_min:
144
+ return True
145
+ return False
146
+
147
+
124
148
  class GenericStage():
125
149
  def __init__(self, stage_name, **kwargs):
126
150
  #Stage Params
@@ -134,7 +158,7 @@ class GenericStage():
134
158
  self.start_time = None
135
159
  self.csv_path = os.path.join(self.test_dir, f'{self.stage_name}.csv')
136
160
  self.stage_tooltip = kwargs.get('stage_tooltip', 'Missing tooltip')
137
- self.error_summary = kwargs.get('error_summary', 'View the stage report for more info')
161
+ self.error_summary = kwargs.get('error_summary', ERR_SUMMARY_DEFAULT)
138
162
 
139
163
  def __repr__(self):
140
164
  return self.stage_name
@@ -159,3 +183,29 @@ class GenericStage():
159
183
  self.add_to_stage_report(f'Stage run time: {datetime.datetime.now() - self.start_time}')
160
184
  self.add_to_stage_report(f'This stage {uncapitalize(self.stage_tooltip)}.')
161
185
  self.add_report_line_separator()
186
+
187
+ def add_report_topic_validation(self, topic:Literal['status', 'data']):
188
+ if self.topic_suffix != '':
189
+ return
190
+ valid_topic, invalid_msg, invalid_topic = self.mqttc.validate_serialization_topic(topic)
191
+ if valid_topic == False:
192
+ # For now not failing stage since the customBroker command include topics explicitly
193
+ # self.stage_pass = MINIMUM_SCORE
194
+ # self.error_summary += "Invalid serialization-topic combination. "
195
+ self.add_to_stage_report(f'Warning: Received message on {invalid_topic} although serialization is {self.mqttc.get_serialization()}')
196
+
197
+ def score_pass(self):
198
+ if self.stage_pass >= self.pass_min:
199
+ return True
200
+ return False
201
+
202
+ def score_inconclusive(self):
203
+ if self.inconclusive_min <= self.stage_pass < self.pass_min:
204
+ return True
205
+ return False
206
+
207
+ def score_fail(self):
208
+ if self.stage_pass < self.inconclusive_min:
209
+ return True
210
+ return False
211
+
@@ -2,6 +2,7 @@ import datetime
2
2
  import time
3
3
  import os
4
4
  from enum import Enum
5
+ from typing import Literal
5
6
 
6
7
  from wiliot_api.api_client import WiliotCloudError
7
8
 
@@ -15,10 +16,13 @@ from gw_certificate.tests.static.references import GW_REGISTER_DOC, GW_MQTT_DOC
15
16
  # HELPER DEFINES
16
17
  REG_CERT_OWNER_ID = 'gw-certification-account'
17
18
  ENV_VAR_AWS = 'WLT_REG_CERT_KEY_AWS'
18
- STAGES_TIMEOUT = 2
19
+
20
+ STAGES_TIMEOUT_MINUTES = 2
19
21
  TOKEN_EXPIRY_MINUTES = 3
22
+ CLOUD_DELAY_SEC = 7
23
+ BUSY_WAIT_DELAY_SEC = 5
24
+ STAGE_START_DELAY_MS = (BUSY_WAIT_DELAY_SEC + CLOUD_DELAY_SEC + 1) * 1000
20
25
 
21
- ERROR_NO_API_KEY = f'You must receive an API security key from wiliot and save if to the environment variable {ENV_VAR_AWS} first.'
22
26
  ERROR_NO_REGISTER = 'Gateway did not register itself in time.'
23
27
  ERROR_NO_ONLINE = 'Gateway did not connect to MQTT in time.'
24
28
  ERROR_NO_ACTIVE = 'Gateway did not upload a status message with its configurations in time.'
@@ -33,13 +37,10 @@ class GetGwField(Enum):
33
37
 
34
38
  class Status(Enum):
35
39
  PRE_REGISTERED = 'pre-registered'
40
+ REGISTERED = 'registered'
36
41
  APPROVED = 'approved'
37
42
  ACTIVE = 'active'
38
43
 
39
- class Online(Enum):
40
- FALSE = False
41
- TRUE = True
42
-
43
44
  class SharedData():
44
45
  """
45
46
  Hold variables which values must be shared between different stages.
@@ -59,7 +60,43 @@ class GenericRegistrationStage(GenericStage):
59
60
  def get_gateway_field(self, field:GetGwField):
60
61
  temp = self.edge.get_gateway(self.gw_id)
61
62
  return temp[field.value]
62
-
63
+
64
+ def kick_gw_from_mqtt(self):
65
+ response = self.edge.kick_gw_from_mqtt(self.gw_id)
66
+ debug_print(f"Kick response:{response}")
67
+
68
+ def validate_kong_logs(self, endpoint:Literal['device-authorize', 'registry', 'token', 'refresh']):
69
+ try:
70
+ message = self.edge.get_kong_logs(self.gw_id)
71
+ except WiliotCloudError as wce:
72
+ wce_dict = wce.args[0]
73
+ status_code = wce_dict.get('status_code')
74
+ msg = wce_dict.get('message')
75
+ if status_code == 404 and 'not found' in msg:
76
+ debug_print("Could not find gw when requesting for logs.")
77
+ debug_print("Either it is not registered, didn't issue any requests, or is missing the X-Gateway-ID header.")
78
+ return False
79
+ elif status_code == None:
80
+ raise wce
81
+ if message.get('status_code') != 200:
82
+ debug_print(f"Failed fetching logs, status_code:{message.get('status_code')}")
83
+ return False
84
+
85
+ # Convert datetime.now() format to epoch in MS
86
+ stage_start_ts = self.start_time.timestamp() * 1000 - STAGE_START_DELAY_MS
87
+
88
+ for log in message['data']:
89
+ if log['timestamp'] > stage_start_ts and endpoint in log['endpoint']:
90
+ response_code = log['responseCode']
91
+ if response_code != 200:
92
+ debug_print(f"An HTTP request to /{endpoint} resulted in an invalid response code:{response_code}")
93
+ else:
94
+ debug_print(f"A valid HTTP request to /{endpoint} was received")
95
+ return True
96
+
97
+ debug_print(f"No valid HTTP request to /{endpoint} was found")
98
+ return False
99
+
63
100
  class RegistryStage(GenericRegistrationStage):
64
101
  def __init__(self, **kwargs):
65
102
  self.__dict__.update(kwargs)
@@ -80,9 +117,13 @@ class RegistryStage(GenericRegistrationStage):
80
117
  msg = wce_dict.get('message')
81
118
  if status_code == 400 and 'already exists' in msg:
82
119
  debug_print(f'{gw_id} already exists in Wiliot platform! Deleting and pre-registering from scratch')
120
+ self.kick_gw_from_mqtt()
83
121
  self.edge.delete_gateway(gw_id)
122
+ time.sleep(CLOUD_DELAY_SEC)
84
123
  pre_registered = self.edge.register_gateway([gw_id])
85
124
  else:
125
+ if status_code == 403:
126
+ debug_print(f"The API key within {self.env_variable} seems invalid. It is not authorized to pre-register the gateway")
86
127
  raise wce
87
128
  return pre_registered
88
129
 
@@ -96,12 +137,16 @@ class RegistryStage(GenericRegistrationStage):
96
137
  def run(self):
97
138
  super().run()
98
139
  debug_print(f"Waiting for the gateway to finish the Registry step..")
99
- timeout = datetime.datetime.now() + datetime.timedelta(minutes=STAGES_TIMEOUT)
140
+ timeout = datetime.datetime.now() + datetime.timedelta(minutes=STAGES_TIMEOUT_MINUTES)
100
141
  self.status = self.get_gateway_field(GetGwField.STATUS)
101
142
  while datetime.datetime.now() < timeout and not any(self.status == s.value for s in {Status.APPROVED, Status.ACTIVE}):
102
- time.sleep(5)
143
+ time.sleep(BUSY_WAIT_DELAY_SEC)
103
144
  self.status = self.get_gateway_field(GetGwField.STATUS)
104
145
 
146
+ time.sleep(CLOUD_DELAY_SEC)
147
+ self.validate_kong_logs('device-authorize')
148
+ self.validate_kong_logs('registry')
149
+
105
150
  def generate_stage_report(self):
106
151
  self.add_report_header()
107
152
  if not any(self.status == s.value for s in {Status.APPROVED, Status.ACTIVE}):
@@ -111,7 +156,8 @@ class RegistryStage(GenericRegistrationStage):
111
156
  debug_print(f"The gateway failed to register. Its status is '{self.status}' while it is expected to be '{Status.APPROVED.value}'.")
112
157
  self.add_to_stage_report(f"There was an error in the Device-authorize or Registry steps.")
113
158
  self.add_to_stage_report(f"Please go over the Device-authorize and Registry sections in this document:\n{GW_REGISTER_DOC}")
114
- # TODO Ideally we should know where the error is exactly and inform the user. We currently lack such resolution
159
+ if self.status == Status.REGISTERED:
160
+ self.add_to_stage_report(f"Highly likely that the gateway is missing the 'X-Gateway-ID' header in it's HTTP requests.")
115
161
  else:
116
162
  self.stage_pass = PERFECT_SCORE
117
163
  self.add_to_stage_report("Device-authorize and Registry requests were issued well.")
@@ -134,12 +180,15 @@ class OnlineStage(GenericRegistrationStage):
134
180
  def run(self):
135
181
  super().run()
136
182
  debug_print(f"Waiting for the gateway to connect to MQTT..")
137
- timeout = datetime.datetime.now() + datetime.timedelta(minutes=STAGES_TIMEOUT)
183
+ timeout = datetime.datetime.now() + datetime.timedelta(minutes=STAGES_TIMEOUT_MINUTES)
138
184
  self.online = self.get_gateway_field(GetGwField.ONLINE)
139
185
  while datetime.datetime.now() < timeout and self.online != True:
140
- time.sleep(5)
186
+ time.sleep(BUSY_WAIT_DELAY_SEC)
141
187
  self.online = self.get_gateway_field(GetGwField.ONLINE)
142
188
 
189
+ time.sleep(CLOUD_DELAY_SEC)
190
+ self.validate_kong_logs('token')
191
+
143
192
  def generate_stage_report(self):
144
193
  self.add_report_header()
145
194
  if self.online != True:
@@ -149,8 +198,7 @@ class OnlineStage(GenericRegistrationStage):
149
198
  self.add_to_stage_report(f"Either it didn't acquire a token or it didn't connect to MQTT in time.")
150
199
  self.add_to_stage_report(f"Please go over the Poll For Token section in:\n{GW_REGISTER_DOC}")
151
200
  self.add_to_stage_report(f"and the MQTT details in:\n{GW_MQTT_DOC}")
152
- debug_print("Gateway did not connect ot MQTT within time limit")
153
- # TODO Ideally we should know where the error is exactly and inform the user. We currently lack such resolution
201
+ debug_print("Gateway did not connect to MQTT within time limit")
154
202
  else:
155
203
  self.stage_pass = PERFECT_SCORE
156
204
  self.add_to_stage_report("Token acquisition and MQTT connection were done succesfully.")
@@ -174,10 +222,10 @@ class ActiveStage(GenericRegistrationStage):
174
222
  def run(self):
175
223
  super().run()
176
224
  debug_print(f"Waiting for the gateway to upload a status message..")
177
- timeout = datetime.datetime.now() + datetime.timedelta(minutes=STAGES_TIMEOUT)
225
+ timeout = datetime.datetime.now() + datetime.timedelta(minutes=STAGES_TIMEOUT_MINUTES)
178
226
  self.status = self.get_gateway_field(GetGwField.STATUS)
179
227
  while datetime.datetime.now() < timeout and self.status != Status.ACTIVE.value:
180
- time.sleep(5)
228
+ time.sleep(BUSY_WAIT_DELAY_SEC)
181
229
  self.status = self.get_gateway_field(GetGwField.STATUS)
182
230
 
183
231
  def generate_stage_report(self):
@@ -212,22 +260,23 @@ class RefreshStage(GenericRegistrationStage):
212
260
  debug_print(f"Waiting for the token to expire..")
213
261
  timeout = self.shared_data.gw_online_ts + datetime.timedelta(minutes=TOKEN_EXPIRY_MINUTES)
214
262
  while datetime.datetime.now() < timeout:
215
- time.sleep(5)
216
-
217
- def kick_gw_from_mqtt():
218
- response = self.edge.kick_gw_from_mqtt(self.gw_id)
219
- debug_print(f"Kick response:{response}")
263
+ time.sleep(BUSY_WAIT_DELAY_SEC)
220
264
 
221
265
  debug_print(f"Token expired, kicking gateway")
222
- kick_gw_from_mqtt()
266
+ self.kick_gw_from_mqtt()
223
267
 
268
+ # Sleep here since it sometimes take time for the cloud to kick and change the gateway's online status
269
+ time.sleep(CLOUD_DELAY_SEC)
224
270
  debug_print(f"Waiting for the gateway to refresh its token and connect to MQTT..")
225
- timeout = datetime.datetime.now() + datetime.timedelta(minutes=STAGES_TIMEOUT)
271
+ timeout = datetime.datetime.now() + datetime.timedelta(minutes=STAGES_TIMEOUT_MINUTES)
226
272
  self.online = self.get_gateway_field(GetGwField.ONLINE)
227
273
  while datetime.datetime.now() < timeout and self.online != True:
228
- time.sleep(5)
274
+ time.sleep(BUSY_WAIT_DELAY_SEC)
229
275
  self.online = self.get_gateway_field(GetGwField.ONLINE)
230
276
 
277
+ time.sleep(CLOUD_DELAY_SEC)
278
+ self.validate_kong_logs('refresh')
279
+
231
280
  def generate_stage_report(self):
232
281
  self.add_report_header()
233
282
  if self.online != True:
@@ -257,9 +306,10 @@ class RegistrationTest(GenericTest):
257
306
 
258
307
  # Set up the edge client for all stages
259
308
  env = '' if self.env == 'prod' else '_' + str(self.env).upper()
260
- api_sec_key = os.environ.get(ENV_VAR_AWS + env)
309
+ self.env_variable = ENV_VAR_AWS + env
310
+ api_sec_key = os.environ.get(self.env_variable)
261
311
  if not api_sec_key:
262
- raise Exception(f"An API security key must be set to the envrionment variable {ENV_VAR_AWS} in order to run the RegistrationTest")
312
+ raise Exception(f"An API security key must be set to the envrionment variable {self.env_variable} in order to run the RegistrationTest")
263
313
  self.edge = ExtendedEdgeClient(api_sec_key, REG_CERT_OWNER_ID, env=self.env)
264
314
 
265
315
  self.shared_data = SharedData()
@@ -275,7 +325,7 @@ class RegistrationTest(GenericTest):
275
325
  stage.prepare_stage()
276
326
  stage.run()
277
327
  self.add_to_test_report(stage.generate_stage_report())
278
- self.test_pass = PassCriteria.calc_for_test(self.test_pass, stage)
328
+ self.test_pass = PassCriteria.calc_for_test(self, stage)
279
329
  if self.test_pass != PERFECT_SCORE and stage != self.stages[-1]:
280
330
  debug_print(f"{type(self).__name__} stopped without running all of its stages since {type(stage).__name__} failed")
281
331
  self.add_to_test_report(f"{type(self).__name__} stopped without running all of its stages since {type(stage).__name__} failed")
@@ -284,5 +334,6 @@ class RegistrationTest(GenericTest):
284
334
 
285
335
  def end_test(self):
286
336
  debug_print(f'Deleting {self.gw_id} from {REG_CERT_OWNER_ID} before exiting')
337
+ time.sleep(CLOUD_DELAY_SEC)
287
338
  self.edge.delete_gateway(self.gw_id)
288
339
  super().end_test()