wiliot-certificate 1.4.0a2__py3-none-any.whl → 1.5.1a1__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 (130) hide show
  1. brg_certificate/ag/energous_v0_defines.py +28 -28
  2. brg_certificate/ag/energous_v1_defines.py +28 -28
  3. brg_certificate/ag/energous_v2_defines.py +28 -28
  4. brg_certificate/ag/energous_v3_defines.py +28 -28
  5. brg_certificate/ag/energous_v4_defines.py +28 -28
  6. brg_certificate/ag/fanstel_lan_v0_defines.py +28 -28
  7. brg_certificate/ag/fanstel_lte_v0_defines.py +28 -28
  8. brg_certificate/ag/fanstel_wifi_v0_defines.py +28 -28
  9. brg_certificate/ag/minew_lte_v0_defines.py +28 -28
  10. brg_certificate/ag/wlt_cmd_if.html +1 -1
  11. brg_certificate/ag/wlt_types.html +3 -4
  12. brg_certificate/ag/wlt_types_ag.py +162 -163
  13. brg_certificate/brg_certificate.py +46 -12
  14. brg_certificate/brg_certificate_cli.py +1 -0
  15. brg_certificate/cert_common.py +31 -42
  16. brg_certificate/cert_config.py +7 -5
  17. brg_certificate/cert_data_sim.py +26 -4
  18. brg_certificate/cert_defines.py +30 -3
  19. brg_certificate/cert_gw_sim.py +12 -8
  20. brg_certificate/cert_mqtt.py +10 -2
  21. brg_certificate/cert_prints.py +7 -5
  22. brg_certificate/cert_protobuf.py +5 -1
  23. brg_certificate/cert_results.py +134 -84
  24. brg_certificate/cert_utils.py +14 -17
  25. brg_certificate/certificate_bcc_sanity_test_list.txt +35 -0
  26. brg_certificate/certificate_bcc_test_list.txt +45 -0
  27. brg_certificate/certificate_sanity_test_list.txt +2 -1
  28. brg_certificate/certificate_test_list.txt +10 -4
  29. brg_certificate/restore_brg.py +2 -0
  30. brg_certificate/tests/calibration/interval_test/interval_test.json +2 -1
  31. brg_certificate/tests/calibration/interval_test/interval_test.py +1 -1
  32. brg_certificate/tests/calibration/output_power_test/output_power_test.json +5 -3
  33. brg_certificate/tests/calibration/output_power_test/output_power_test.py +1 -1
  34. brg_certificate/tests/calibration/pattern_test/pattern_test.json +5 -2
  35. brg_certificate/tests/calibration/pattern_test/pattern_test.py +1 -1
  36. brg_certificate/tests/datapath/aging_test/aging_test.json +20 -0
  37. brg_certificate/tests/datapath/aging_test/aging_test.py +135 -0
  38. brg_certificate/tests/datapath/num_of_tags_test/num_of_tags_test.json +8 -3
  39. brg_certificate/tests/datapath/num_of_tags_test/num_of_tags_test.py +2 -2
  40. brg_certificate/tests/datapath/output_power_test/output_power_test.json +5 -2
  41. brg_certificate/tests/datapath/output_power_test/output_power_test.py +1 -1
  42. brg_certificate/tests/datapath/pacer_interval_ble5_test/pacer_interval_ble5_test.json +5 -2
  43. brg_certificate/tests/datapath/pacer_interval_ble5_test/pacer_interval_ble5_test.py +1 -1
  44. brg_certificate/tests/datapath/pacer_interval_tags_count_test/pacer_interval_tags_count_test.json +5 -2
  45. brg_certificate/tests/datapath/pacer_interval_tags_count_test/pacer_interval_tags_count_test.py +2 -2
  46. brg_certificate/tests/datapath/pacer_interval_test/pacer_interval_test.json +5 -2
  47. brg_certificate/tests/datapath/pacer_interval_test/pacer_interval_test.py +1 -1
  48. brg_certificate/tests/datapath/pattern_test/pattern_test.json +6 -3
  49. brg_certificate/tests/datapath/pattern_test/pattern_test.py +1 -1
  50. brg_certificate/tests/datapath/pkt_filter_ble5_test/pkt_filter_ble5_test.json +8 -2
  51. brg_certificate/tests/datapath/pkt_filter_ble5_test/pkt_filter_ble5_test.py +1 -1
  52. brg_certificate/tests/datapath/pkt_filter_gen3_test/pkt_filter_gen3_test.json +8 -2
  53. brg_certificate/tests/datapath/pkt_filter_gen3_test/pkt_filter_gen3_test.py +1 -1
  54. brg_certificate/tests/datapath/pkt_filter_test/pkt_filter_test.json +8 -2
  55. brg_certificate/tests/datapath/pkt_filter_test/pkt_filter_test.py +1 -1
  56. brg_certificate/tests/datapath/rssi_threshold_test/rssi_threshold_test.json +6 -2
  57. brg_certificate/tests/datapath/rssi_threshold_test/rssi_threshold_test.py +1 -1
  58. brg_certificate/tests/datapath/rx_channel_test/rx_channel_test.json +5 -2
  59. brg_certificate/tests/datapath/rx_channel_test/rx_channel_test.py +1 -1
  60. brg_certificate/tests/datapath/rx_rate_gen2_test/rx_rate_gen2_test.json +3 -4
  61. brg_certificate/tests/datapath/rx_rate_gen2_test/rx_rate_gen2_test.py +1 -1
  62. brg_certificate/tests/datapath/rx_rate_gen3_test/rx_rate_gen3_test.json +3 -4
  63. brg_certificate/tests/datapath/rx_rate_gen3_test/rx_rate_gen3_test.py +1 -1
  64. brg_certificate/tests/datapath/stress_gen3_test/stress_gen3_test.json +14 -22
  65. brg_certificate/tests/datapath/stress_gen3_test/stress_gen3_test.py +24 -24
  66. brg_certificate/tests/datapath/stress_test/stress_test.json +11 -18
  67. brg_certificate/tests/datapath/stress_test/stress_test.py +20 -27
  68. brg_certificate/tests/datapath/tx_repetition_algo_test/tx_repetition_algo_test.json +6 -2
  69. brg_certificate/tests/datapath/tx_repetition_algo_test/tx_repetition_algo_test.py +1 -1
  70. brg_certificate/tests/datapath/tx_repetition_test/tx_repetition_test.json +6 -2
  71. brg_certificate/tests/datapath/tx_repetition_test/tx_repetition_test.py +1 -1
  72. brg_certificate/tests/edge_mgmt/actions_test/actions_test.json +2 -1
  73. brg_certificate/tests/edge_mgmt/actions_test/actions_test.py +4 -24
  74. brg_certificate/tests/edge_mgmt/brg2brg_ota_ble5_test/brg2brg_ota_ble5_test.json +2 -1
  75. brg_certificate/tests/edge_mgmt/brg2brg_ota_ble5_test/brg2brg_ota_ble5_test.py +1 -1
  76. brg_certificate/tests/edge_mgmt/brg2brg_ota_test/brg2brg_ota_test.json +2 -1
  77. brg_certificate/tests/edge_mgmt/brg2brg_ota_test/brg2brg_ota_test.py +1 -1
  78. brg_certificate/tests/edge_mgmt/leds_test/leds_test.json +9 -5
  79. brg_certificate/tests/edge_mgmt/leds_test/leds_test.py +4 -4
  80. brg_certificate/tests/edge_mgmt/ota_test/ota_test.json +9 -5
  81. brg_certificate/tests/edge_mgmt/ota_test/ota_test.py +45 -1
  82. brg_certificate/tests/edge_mgmt/stat_test/stat_test.json +2 -1
  83. brg_certificate/tests/edge_mgmt/stat_test/stat_test.py +1 -1
  84. brg_certificate/tests/energy2400/duty_cycle_test/duty_cycle_test.json +5 -2
  85. brg_certificate/tests/energy2400/duty_cycle_test/duty_cycle_test.py +1 -1
  86. brg_certificate/tests/energy2400/output_power_test/output_power_test.json +5 -3
  87. brg_certificate/tests/energy2400/output_power_test/output_power_test.py +1 -1
  88. brg_certificate/tests/energy2400/pattern_test/pattern_test.json +5 -2
  89. brg_certificate/tests/energy2400/pattern_test/pattern_test.py +1 -1
  90. brg_certificate/tests/energy2400/signal_indicator_ble5_10_250k_test/signal_indicator_ble5_10_250k_test.json +20 -0
  91. brg_certificate/tests/energy2400/signal_indicator_ble5_10_250k_test/signal_indicator_ble5_10_250k_test.py +346 -0
  92. brg_certificate/tests/energy2400/signal_indicator_ble5_10_500k_test/signal_indicator_ble5_10_500k_test.json +20 -0
  93. brg_certificate/tests/energy2400/signal_indicator_ble5_10_500k_test/signal_indicator_ble5_10_500k_test.py +346 -0
  94. brg_certificate/tests/energy2400/signal_indicator_sub1g_2_4_test/signal_indicator_sub1g_2_4_test.json +2 -1
  95. brg_certificate/tests/energy2400/signal_indicator_sub1g_2_4_test/signal_indicator_sub1g_2_4_test.py +1 -1
  96. brg_certificate/tests/energy2400/signal_indicator_test/signal_indicator_test.json +12 -5
  97. brg_certificate/tests/energy2400/signal_indicator_test/signal_indicator_test.py +130 -43
  98. brg_certificate/tests/energy_sub1g/duty_cycle_test/duty_cycle_test.json +5 -2
  99. brg_certificate/tests/energy_sub1g/duty_cycle_test/duty_cycle_test.py +1 -1
  100. brg_certificate/tests/energy_sub1g/pattern_test/pattern_test.json +9 -3
  101. brg_certificate/tests/energy_sub1g/pattern_test/pattern_test.py +1 -1
  102. brg_certificate/tests/energy_sub1g/signal_indicator_functionality_test/signal_indicator_functionality_test.json +2 -1
  103. brg_certificate/tests/energy_sub1g/signal_indicator_functionality_test/signal_indicator_functionality_test.py +1 -1
  104. brg_certificate/tests/energy_sub1g/signal_indicator_test/signal_indicator_test.json +5 -2
  105. brg_certificate/tests/energy_sub1g/signal_indicator_test/signal_indicator_test.py +1 -1
  106. brg_certificate/wltPb_pb2.py +50 -38
  107. brg_certificate/wltPb_pb2.pyi +40 -34
  108. brg_certificate/wlt_types.py +4 -6
  109. common/wlt_logo.png +0 -0
  110. gw_certificate/ag/ut_defines.py +4 -1
  111. gw_certificate/cert_results.py +145 -0
  112. gw_certificate/gw_certificate.py +18 -6
  113. gw_certificate/gw_certificate_cli.py +3 -3
  114. gw_certificate/interface/mqtt.py +1 -0
  115. gw_certificate/interface/uart_if.py +1 -1
  116. gw_certificate/tests/actions.py +7 -2
  117. gw_certificate/tests/connection.py +1 -1
  118. gw_certificate/tests/generic.py +43 -17
  119. gw_certificate/tests/registration.py +2 -1
  120. gw_certificate/tests/uplink.py +26 -35
  121. {wiliot_certificate-1.4.0a2.dist-info → wiliot_certificate-1.5.1a1.dist-info}/METADATA +16 -10
  122. {wiliot_certificate-1.4.0a2.dist-info → wiliot_certificate-1.5.1a1.dist-info}/RECORD +126 -120
  123. {wiliot_certificate-1.4.0a2.dist-info → wiliot_certificate-1.5.1a1.dist-info}/WHEEL +1 -1
  124. {wiliot_certificate-1.4.0a2.dist-info → wiliot_certificate-1.5.1a1.dist-info}/top_level.txt +1 -0
  125. brg_certificate/tests/datapath/adaptive_pacer_algo_test/adaptive_pacer_algo_test.json +0 -13
  126. brg_certificate/tests/datapath/adaptive_pacer_algo_test/adaptive_pacer_algo_test.py +0 -76
  127. brg_certificate/tests/energy2400/signal_indicator_ble5_test/signal_indicator_ble5_test.json +0 -13
  128. brg_certificate/tests/energy2400/signal_indicator_ble5_test/signal_indicator_ble5_test.py +0 -398
  129. {wiliot_certificate-1.4.0a2.dist-info → wiliot_certificate-1.5.1a1.dist-info}/entry_points.txt +0 -0
  130. {wiliot_certificate-1.4.0a2.dist-info → wiliot_certificate-1.5.1a1.dist-info/licenses}/LICENSE +0 -0
@@ -62,6 +62,28 @@ class UplinkMessage(_message.Message):
62
62
  actionStatus: ActionStatus
63
63
  def __init__(self, gatewayStatus: _Optional[_Union[GatewayStatus, _Mapping]] = ..., gatewayInfo: _Optional[_Union[GatewayInfo, _Mapping]] = ..., gatewayLogs: _Optional[_Union[GatewayLogs, _Mapping]] = ..., actionStatus: _Optional[_Union[ActionStatus, _Mapping]] = ...) -> None: ...
64
64
 
65
+ class ACL(_message.Message):
66
+ __slots__ = ("mode_allow", "ids")
67
+ MODE_ALLOW_FIELD_NUMBER: _ClassVar[int]
68
+ IDS_FIELD_NUMBER: _ClassVar[int]
69
+ mode_allow: bool
70
+ ids: _containers.RepeatedScalarFieldContainer[bytes]
71
+ def __init__(self, mode_allow: bool = ..., ids: _Optional[_Iterable[bytes]] = ...) -> None: ...
72
+
73
+ class GatewayConfigValue(_message.Message):
74
+ __slots__ = ("integerValue", "numberValue", "stringValue", "boolValue", "aclValue")
75
+ INTEGERVALUE_FIELD_NUMBER: _ClassVar[int]
76
+ NUMBERVALUE_FIELD_NUMBER: _ClassVar[int]
77
+ STRINGVALUE_FIELD_NUMBER: _ClassVar[int]
78
+ BOOLVALUE_FIELD_NUMBER: _ClassVar[int]
79
+ ACLVALUE_FIELD_NUMBER: _ClassVar[int]
80
+ integerValue: int
81
+ numberValue: float
82
+ stringValue: str
83
+ boolValue: bool
84
+ aclValue: ACL
85
+ def __init__(self, integerValue: _Optional[int] = ..., numberValue: _Optional[float] = ..., stringValue: _Optional[str] = ..., boolValue: bool = ..., aclValue: _Optional[_Union[ACL, _Mapping]] = ...) -> None: ...
86
+
65
87
  class GatewayStatus(_message.Message):
66
88
  __slots__ = ("gatewayId", "gatewayType", "downlinkSupported", "bridgeOtaUpgradeSupported", "apiVersion", "version", "bleSwVersion", "interfaceSwVersion", "location", "config", "bleAddress")
67
89
  class ConfigEntry(_message.Message):
@@ -69,8 +91,8 @@ class GatewayStatus(_message.Message):
69
91
  KEY_FIELD_NUMBER: _ClassVar[int]
70
92
  VALUE_FIELD_NUMBER: _ClassVar[int]
71
93
  key: str
72
- value: Value
73
- def __init__(self, key: _Optional[str] = ..., value: _Optional[_Union[Value, _Mapping]] = ...) -> None: ...
94
+ value: GatewayConfigValue
95
+ def __init__(self, key: _Optional[str] = ..., value: _Optional[_Union[GatewayConfigValue, _Mapping]] = ...) -> None: ...
74
96
  GATEWAYID_FIELD_NUMBER: _ClassVar[int]
75
97
  GATEWAYTYPE_FIELD_NUMBER: _ClassVar[int]
76
98
  DOWNLINKSUPPORTED_FIELD_NUMBER: _ClassVar[int]
@@ -91,9 +113,9 @@ class GatewayStatus(_message.Message):
91
113
  bleSwVersion: str
92
114
  interfaceSwVersion: str
93
115
  location: Location
94
- config: _containers.MessageMap[str, Value]
116
+ config: _containers.MessageMap[str, GatewayConfigValue]
95
117
  bleAddress: str
96
- def __init__(self, gatewayId: _Optional[str] = ..., gatewayType: _Optional[str] = ..., downlinkSupported: bool = ..., bridgeOtaUpgradeSupported: bool = ..., apiVersion: _Optional[int] = ..., version: _Optional[str] = ..., bleSwVersion: _Optional[str] = ..., interfaceSwVersion: _Optional[str] = ..., location: _Optional[_Union[Location, _Mapping]] = ..., config: _Optional[_Mapping[str, Value]] = ..., bleAddress: _Optional[str] = ...) -> None: ...
118
+ def __init__(self, gatewayId: _Optional[str] = ..., gatewayType: _Optional[str] = ..., downlinkSupported: bool = ..., bridgeOtaUpgradeSupported: bool = ..., apiVersion: _Optional[int] = ..., version: _Optional[str] = ..., bleSwVersion: _Optional[str] = ..., interfaceSwVersion: _Optional[str] = ..., location: _Optional[_Union[Location, _Mapping]] = ..., config: _Optional[_Mapping[str, GatewayConfigValue]] = ..., bleAddress: _Optional[str] = ...) -> None: ...
97
119
 
98
120
  class GatewayInfo(_message.Message):
99
121
  __slots__ = ("entries",)
@@ -115,28 +137,32 @@ class GatewayLogs(_message.Message):
115
137
  def __init__(self, logs: _Optional[_Iterable[str]] = ...) -> None: ...
116
138
 
117
139
  class ActionStatus(_message.Message):
118
- __slots__ = ("action", "status")
140
+ __slots__ = ("action", "status", "step", "progress", "bridgeId")
119
141
  ACTION_FIELD_NUMBER: _ClassVar[int]
120
142
  STATUS_FIELD_NUMBER: _ClassVar[int]
143
+ STEP_FIELD_NUMBER: _ClassVar[int]
144
+ PROGRESS_FIELD_NUMBER: _ClassVar[int]
145
+ BRIDGEID_FIELD_NUMBER: _ClassVar[int]
121
146
  action: int
122
147
  status: int
123
- def __init__(self, action: _Optional[int] = ..., status: _Optional[int] = ...) -> None: ...
148
+ step: int
149
+ progress: int
150
+ bridgeId: bytes
151
+ def __init__(self, action: _Optional[int] = ..., status: _Optional[int] = ..., step: _Optional[int] = ..., progress: _Optional[int] = ..., bridgeId: _Optional[bytes] = ...) -> None: ...
124
152
 
125
153
  class DownlinkMessage(_message.Message):
126
- __slots__ = ("txPacket", "gatewayAction", "bridgeUpgrade", "gatewayConfig", "customBroker", "customMessage")
154
+ __slots__ = ("txPacket", "gatewayAction", "bridgeUpgrade", "gatewayConfig", "customMessage")
127
155
  TXPACKET_FIELD_NUMBER: _ClassVar[int]
128
156
  GATEWAYACTION_FIELD_NUMBER: _ClassVar[int]
129
157
  BRIDGEUPGRADE_FIELD_NUMBER: _ClassVar[int]
130
158
  GATEWAYCONFIG_FIELD_NUMBER: _ClassVar[int]
131
- CUSTOMBROKER_FIELD_NUMBER: _ClassVar[int]
132
159
  CUSTOMMESSAGE_FIELD_NUMBER: _ClassVar[int]
133
160
  txPacket: TxPacket
134
161
  gatewayAction: GatewayAction
135
162
  bridgeUpgrade: BridgeUpgrade
136
163
  gatewayConfig: GatewayConfig
137
- customBroker: CustomBroker
138
164
  customMessage: CustomMessage
139
- def __init__(self, txPacket: _Optional[_Union[TxPacket, _Mapping]] = ..., gatewayAction: _Optional[_Union[GatewayAction, _Mapping]] = ..., bridgeUpgrade: _Optional[_Union[BridgeUpgrade, _Mapping]] = ..., gatewayConfig: _Optional[_Union[GatewayConfig, _Mapping]] = ..., customBroker: _Optional[_Union[CustomBroker, _Mapping]] = ..., customMessage: _Optional[_Union[CustomMessage, _Mapping]] = ...) -> None: ...
165
+ def __init__(self, txPacket: _Optional[_Union[TxPacket, _Mapping]] = ..., gatewayAction: _Optional[_Union[GatewayAction, _Mapping]] = ..., bridgeUpgrade: _Optional[_Union[BridgeUpgrade, _Mapping]] = ..., gatewayConfig: _Optional[_Union[GatewayConfig, _Mapping]] = ..., customMessage: _Optional[_Union[CustomMessage, _Mapping]] = ...) -> None: ...
140
166
 
141
167
  class TxPacket(_message.Message):
142
168
  __slots__ = ("payload", "maxRetries", "maxDurationMs")
@@ -179,8 +205,8 @@ class GatewayConfig(_message.Message):
179
205
  KEY_FIELD_NUMBER: _ClassVar[int]
180
206
  VALUE_FIELD_NUMBER: _ClassVar[int]
181
207
  key: str
182
- value: Value
183
- def __init__(self, key: _Optional[str] = ..., value: _Optional[_Union[Value, _Mapping]] = ...) -> None: ...
208
+ value: GatewayConfigValue
209
+ def __init__(self, key: _Optional[str] = ..., value: _Optional[_Union[GatewayConfigValue, _Mapping]] = ...) -> None: ...
184
210
  VERSION_FIELD_NUMBER: _ClassVar[int]
185
211
  BLESWVERSION_FIELD_NUMBER: _ClassVar[int]
186
212
  INTERFACESWVERSION_FIELD_NUMBER: _ClassVar[int]
@@ -190,28 +216,8 @@ class GatewayConfig(_message.Message):
190
216
  bleSwVersion: str
191
217
  interfaceSwVersion: str
192
218
  location: Location
193
- config: _containers.MessageMap[str, Value]
194
- def __init__(self, version: _Optional[str] = ..., bleSwVersion: _Optional[str] = ..., interfaceSwVersion: _Optional[str] = ..., location: _Optional[_Union[Location, _Mapping]] = ..., config: _Optional[_Mapping[str, Value]] = ...) -> None: ...
195
-
196
- class CustomBroker(_message.Message):
197
- __slots__ = ("customBroker", "port", "brokerUrl", "username", "password", "updateTopic", "statusTopic", "dataTopic")
198
- CUSTOMBROKER_FIELD_NUMBER: _ClassVar[int]
199
- PORT_FIELD_NUMBER: _ClassVar[int]
200
- BROKERURL_FIELD_NUMBER: _ClassVar[int]
201
- USERNAME_FIELD_NUMBER: _ClassVar[int]
202
- PASSWORD_FIELD_NUMBER: _ClassVar[int]
203
- UPDATETOPIC_FIELD_NUMBER: _ClassVar[int]
204
- STATUSTOPIC_FIELD_NUMBER: _ClassVar[int]
205
- DATATOPIC_FIELD_NUMBER: _ClassVar[int]
206
- customBroker: bool
207
- port: int
208
- brokerUrl: str
209
- username: str
210
- password: str
211
- updateTopic: str
212
- statusTopic: str
213
- dataTopic: str
214
- def __init__(self, customBroker: bool = ..., port: _Optional[int] = ..., brokerUrl: _Optional[str] = ..., username: _Optional[str] = ..., password: _Optional[str] = ..., updateTopic: _Optional[str] = ..., statusTopic: _Optional[str] = ..., dataTopic: _Optional[str] = ...) -> None: ...
219
+ config: _containers.MessageMap[str, GatewayConfigValue]
220
+ def __init__(self, version: _Optional[str] = ..., bleSwVersion: _Optional[str] = ..., interfaceSwVersion: _Optional[str] = ..., location: _Optional[_Union[Location, _Mapping]] = ..., config: _Optional[_Mapping[str, GatewayConfigValue]] = ...) -> None: ...
215
221
 
216
222
  class CustomMessage(_message.Message):
217
223
  __slots__ = ("entries",)
@@ -92,16 +92,11 @@ class WltPkt():
92
92
  self.pkt = ag.UnifiedEchoPktV1()
93
93
  elif self.data_hdr.group_id_major == ag.GROUP_ID_BLE5_EXTENDED:
94
94
  self.pkt = ag.UnifiedEchoExtPkt()
95
- else:
96
- print(f"Unidentified unified group id found: {hex(self.data_hdr.group_id_major)}")
97
95
  # SideInfo pkts
98
96
  elif self.hdr.group_id == ag.GROUP_ID_SIDE_INFO_SENSOR:
99
97
  self.pkt = ag.SideInfoSensor()
100
98
  elif self.hdr.group_id == ag.GROUP_ID_SIDE_INFO:
101
99
  self.pkt = ag.SideInfo()
102
- else:
103
- print(f"Unidentified sensor group id found: {hex(self.data_hdr.group_id_major)}")
104
-
105
100
  if self.pkt:
106
101
  if self.data_hdr.group_id_major == ag.GROUP_ID_BLE5_EXTENDED:
107
102
  self.pkt.set(string[14:84])
@@ -111,4 +106,7 @@ class WltPkt():
111
106
  elif self.hdr.group_id == ag.GROUP_ID_SIGNAL_INDICATOR:
112
107
  self.pkt = eval_pkt(f'SignalIndicatorDataV{ag.SIGNAL_INDICATOR_PACKET_VERSION_LATEST}')(string[8:62])
113
108
  elif self.hdr.uuid_lsb == ag.HDR_DEFAULT_BRG_SENSOR_UUID_LSB and self.hdr.uuid_msb == ag.HDR_DEFAULT_BRG_SENSOR_UUID_MSB:
114
- self.pkt = ag.SensorData(string)
109
+ self.pkt = ag.SensorData(string)
110
+ # Unparsed pkts
111
+ else:
112
+ print(f"Unable to parse packet with payload: {string}")
common/wlt_logo.png ADDED
Binary file
@@ -164,9 +164,12 @@ GLOBAL_PACING_GROUP_THRESHOLD = 0.70
164
164
  PACKETS_ECHO_OFF = 16
165
165
  TEST_PASSED = 0
166
166
  TEST_FAILED = -1
167
+ TEST_INCONCLUSIVE = 1
168
+ TEST_INFO = 2
169
+ TEST_WARNING = 3
170
+ TEST_OPTIONAL = 4
167
171
  NO_RESPONSE = "NO_RESPONSE"
168
172
  DONE = "DONE"
169
- TEST_SUCCESS = ":)"
170
173
  MGMT_PKT = "mgmt_pkt"
171
174
  UNIFIED_PKT = "unified_pkt"
172
175
  SIDE_INFO_PKT = "side_info_pkt"
@@ -0,0 +1,145 @@
1
+ import os
2
+ import tabulate
3
+ from reportlab.lib import colors
4
+ from reportlab.lib.pagesizes import letter
5
+ from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer, PageBreak, KeepTogether, Image
6
+ from reportlab.lib.styles import ParagraphStyle
7
+ from reportlab.lib.enums import TA_CENTER, TA_LEFT
8
+
9
+ # Local imports
10
+ from gw_certificate.ag.ut_defines import TEST_FAILED, TEST_INCONCLUSIVE, TEST_PASSED, TEST_INFO, TEST_WARNING, TEST_OPTIONAL
11
+ BASE_DIR = os.path.dirname(os.path.abspath(__file__))
12
+ format_timedelta = lambda delta: f"{int(delta.total_seconds()//3600):02}:{int((delta.total_seconds()%3600)//60):02}:{int(delta.total_seconds()%60):02}"
13
+
14
+ ##################################
15
+ # GENERIC
16
+ ##################################
17
+ def generate_pdf_results_file(gw_cert):
18
+ # Extract GW certificate tests results
19
+ failures, inconclusive = 0, 0
20
+ for test in gw_cert.tests:
21
+ if test.rc == TEST_INCONCLUSIVE:
22
+ inconclusive += 1
23
+ elif test.rc == TEST_FAILED:
24
+ failures += 1
25
+
26
+ # Generate PDF file
27
+ doc = SimpleDocTemplate(gw_cert.result_pdf_path, pagesize=letter)
28
+ doc.title = f"Wiliot Gateway Certificate Results"
29
+ elements, hdr_page = [], []
30
+
31
+ # Add Wiliot Logo
32
+ img = Image(os.path.join(BASE_DIR, "../common", "wlt_logo.png"), width=100, height=40) # Adjust size as needed
33
+ hdr_page.append(img)
34
+ hdr_page.append(Spacer(1, 20))
35
+
36
+ # Title and Summary
37
+ red_header = STYLES_PDF.get("RED_HEADER", ParagraphStyle("Default"))
38
+ green_header = STYLES_PDF.get("GREEN_HEADER", ParagraphStyle("Default"))
39
+ module_header = STYLES_PDF.get("MODULE_HEADER", ParagraphStyle("Default"))
40
+ test_header = STYLES_PDF.get("TEST_HEADER", ParagraphStyle("Default"))
41
+ text_style_bold = STYLES_PDF.get("BLACK_BOLD", ParagraphStyle("Default"))
42
+ text_style_centered = STYLES_PDF.get("BLACK", ParagraphStyle("Default"))
43
+ if gw_cert.error:
44
+ title = Paragraph(f"<b>Wiliot Gateway Certificate Error!</b>", red_header)
45
+ hdr_page.append(title)
46
+ hdr_page.append(Spacer(1, 20))
47
+ hdr_page.append(Paragraph(f"{gw_cert.error}", text_style_bold))
48
+ else:
49
+ title = Paragraph(f"<b>Wiliot Gateway Certificate Passed!</b>", green_header) if not failures else Paragraph(f"<b>Wiliot Gateway Certificate Failed!</b>", red_header)
50
+ hdr_page.append(title)
51
+ hdr_page.append(Spacer(1, 20))
52
+ hdr_page.append(Paragraph(f"<b>Summary</b>", module_header))
53
+ hdr_page.append(Spacer(1, 20))
54
+ hdr_page.append(Paragraph("<u>Run Info:</u>", text_style_bold))
55
+ hdr_page.append(Paragraph(f"Run date: {gw_cert.current_datetime.strftime('%d/%m/%Y, %H:%M:%S')}", text_style_bold))
56
+ hdr_page.append(Paragraph(f"Tests duration: {format_timedelta(gw_cert.runtime())}", text_style_bold))
57
+ hdr_page.append(Paragraph(f"Certificate version: {gw_cert.gw_cert_version}", text_style_bold))
58
+ hdr_page.append(Spacer(1, 10))
59
+ if gw_cert.use_uart:
60
+ hdr_page.append(Paragraph("<u>Certification Kit Info:</u>", text_style_bold))
61
+ hdr_page.append(Paragraph(f"BLE simulator mac: {gw_cert.uart.mac}", text_style_bold))
62
+ hdr_page.append(Paragraph(f"BLE simulator version: {gw_cert.uart.fw_version}", text_style_bold))
63
+ hdr_page.append(Spacer(1, 10))
64
+ hdr_page.append(Paragraph("<u>Tested Device Info:</u>", text_style_bold))
65
+ hdr_page.append(Paragraph(f"Tested gateway ID: {gw_cert.gw_id}", text_style_bold))
66
+ hdr_page.append(Spacer(1, 20))
67
+
68
+ # Count Table
69
+ count_data = [
70
+ ["PASSED", "INCONCLUSIVE", "FAILED", "TOTAL"],
71
+ [len(gw_cert.tests)-(failures+inconclusive), inconclusive, failures, len(gw_cert.tests)]
72
+ ]
73
+ count_table = Table(count_data)
74
+ count_table.setStyle(INNER_TABLE_STYLE)
75
+ hdr_page.append(count_table)
76
+ hdr_page.append(Spacer(1, 20))
77
+
78
+ # Test Results
79
+ summary_data = []
80
+ text_style_center = STYLES_PDF.get("BLACK", ParagraphStyle("Default"))
81
+ text_style_left = STYLES_PDF.get("BLACK_LEFT", ParagraphStyle("Default"))
82
+ for test in gw_cert.tests:
83
+ summary_data += [[Paragraph(f'<a href="#{test}">{test}</a>', text_style_centered), pass_or_fail_pdf(test), format_timedelta(test.duration)]]
84
+ elements.append(Paragraph(f"<a name='{test}'/><b>{test}</b>", module_header))
85
+ elements.append(Spacer(1, 20))
86
+ elements.append(pass_or_fail_pdf(test))
87
+ elements.append(Spacer(1, 10))
88
+ elements.append(Paragraph(f"Test duration: {format_timedelta(test.duration)}", text_style_bold))
89
+ elements.append(Spacer(1, 10))
90
+ inner_table, stages_breakdown = [["Phase", "Result", "Duration"]], []
91
+ for stage in test.stages:
92
+ stages_breakdown += [KeepTogether([Paragraph(stage.stage_name, test_header), Spacer(1, 10), pass_or_fail_pdf(stage), Spacer(1, 10)]
93
+ + [Paragraph(l, text_style_left) for l in stage.report.split('\n')]
94
+ + [Spacer(1, 10)])]
95
+ inner_table += [[Paragraph(stage.stage_name, text_style_center), pass_or_fail_pdf(stage), Paragraph(format_timedelta(stage.duration), text_style_center)]]
96
+ test_table = Table(inner_table)
97
+ test_table.setStyle(INNER_TABLE_STYLE)
98
+ elements.append(test_table)
99
+ elements.append(Spacer(1, 20))
100
+ elements += stages_breakdown
101
+ elements.append(PageBreak())
102
+ summary_table = Table([["Name", "Result", "Duration"]] + summary_data)
103
+ summary_table.setStyle(INNER_TABLE_STYLE)
104
+ elements = hdr_page + [summary_table, PageBreak()] + elements
105
+
106
+ doc.build(elements)
107
+
108
+
109
+ ##################################
110
+ # PDF
111
+ ##################################
112
+ STYLES_PDF = {
113
+ "GREEN_HEADER": ParagraphStyle("Green Header", fontName="Helvetica-Bold", fontSize=20, textColor=colors.green, alignment=TA_CENTER),
114
+ "RED_HEADER": ParagraphStyle("Red Header", fontName="Helvetica-Bold", fontSize=20, textColor=colors.red, alignment=TA_CENTER),
115
+ "MODULE_HEADER": ParagraphStyle("Module Header", fontName="Helvetica-Bold", fontSize=16, textColor=colors.navy, alignment=TA_CENTER),
116
+ "TEST_HEADER": ParagraphStyle("Test Header", fontName="Helvetica-Bold", fontSize=12, textColor=colors.black, alignment=TA_CENTER),
117
+ "BLACK": ParagraphStyle("Black", fontName="Helvetica", fontSize=9, textColor=colors.black, splitLongWords=False, alignment=TA_CENTER, wordWrap = 'CJK'),
118
+ "BLACK_LEFT": ParagraphStyle("Black Left", fontName="Helvetica", fontSize=9, textColor=colors.black, splitLongWords=False, alignment=TA_LEFT, wordWrap = 'CJK'),
119
+ "BLACK_BOLD": ParagraphStyle("Black Bold", fontName="Helvetica-Bold", fontSize=9, textColor=colors.black, splitLongWords=False, alignment=TA_LEFT, wordWrap = 'CJK'),
120
+ "BLUE": ParagraphStyle("Blue", fontName="Helvetica-Bold", fontSize=9, textColor=colors.navy, splitLongWords=False, alignment=TA_CENTER),
121
+ "CYAN": ParagraphStyle("Cyan", fontName="Helvetica-Bold", fontSize=9, textColor=colors.cyan, splitLongWords=False, alignment=TA_CENTER),
122
+ "GREEN": ParagraphStyle("Green", fontName="Helvetica-Bold", fontSize=9, textColor=colors.green, splitLongWords=False, alignment=TA_CENTER),
123
+ "WARNING": ParagraphStyle("Warning", fontName="Helvetica-Bold", fontSize=9, textColor=colors.gold, splitLongWords=False, alignment=TA_CENTER),
124
+ "RED": ParagraphStyle("Red", fontName="Helvetica-Bold", fontSize=9, textColor=colors.red, splitLongWords=False, alignment=TA_CENTER),
125
+ "GRAY": ParagraphStyle("Gray", fontName="Helvetica-Bold", fontSize=9, textColor=colors.gray, splitLongWords=False, alignment=TA_CENTER),
126
+ }
127
+ def color_pdf(c, t):
128
+ style = STYLES_PDF.get(c, ParagraphStyle("Default"))
129
+ return Paragraph(t, style)
130
+ pdf_result_map = {TEST_FAILED: color_pdf("RED", "FAILED"), TEST_INCONCLUSIVE: color_pdf("WARNING", "INCONCLUSIVE"),
131
+ TEST_PASSED: color_pdf("GREEN", "PASSED"), TEST_INFO: color_pdf("CYAN", "INFO"),
132
+ TEST_WARNING: color_pdf("WARNING", "WARNING"), TEST_OPTIONAL: color_pdf("GRAY", "OPTIONAL")}
133
+ pass_or_fail_pdf = lambda obj : pdf_result_map[obj.rc]
134
+
135
+ INNER_TABLE_STYLE = TableStyle([
136
+ ('BACKGROUND', (0, 0), (-1, 0), colors.grey),
137
+ ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
138
+ ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
139
+ ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
140
+ ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
141
+ ('FONTSIZE', (0, 0), (-1, 0), 9),
142
+ ('BOTTOMPADDING', (0, 0), (-1, 0), 12),
143
+ ('BACKGROUND', (0, 1), (-1, -1), colors.whitesmoke),
144
+ ('WORDWRAP', (0, 0), (-1, -1), False),
145
+ ])
@@ -20,6 +20,7 @@ from gw_certificate.tests import *
20
20
  from gw_certificate.interface.uart_ports import get_uart_ports
21
21
  from gw_certificate.api_if.gw_capabilities import GWCapabilities
22
22
  from gw_certificate.tests import TESTS_NO_UART
23
+ import gw_certificate.cert_results as cert_results
23
24
 
24
25
  GW_CERT_VERSION = importlib.metadata.version("wiliot-certificate")
25
26
 
@@ -45,14 +46,16 @@ class GWCertificate:
45
46
  aggregation_time=0, env='prod'):
46
47
  # Runtime
47
48
  self.env_dirs = WiliotDir()
48
- self.current_datetime = datetime.datetime.now().strftime('%Y%m%d_%H%M%S')
49
- self.certificate_dir = os.path.join(self.env_dirs.get_wiliot_root_app_dir(), 'gw-certificate', self.current_datetime)
49
+ self.current_datetime = datetime.datetime.now()
50
+ self.duration = None
51
+ self.certificate_dir = os.path.join(self.env_dirs.get_wiliot_root_app_dir(), 'gw-certificate', self.current_datetime.strftime('%Y%m%d_%H%M%S'))
50
52
  self.env_dirs.create_dir(self.certificate_dir)
51
53
  self.logger_filename = initialize_logger(self.certificate_dir)
52
54
  self.logger_filepath = os.path.join(self.certificate_dir, f'{self.logger_filename}.log')
53
55
  self.mqtt_logger_filepath = os.path.join(self.certificate_dir, f'{self.logger_filename}_mqtt.log')
54
56
  self.sniffer_logger_filepath = os.path.join(self.certificate_dir, f'{self.logger_filename}_sniffer.log')
55
- self.result_html_path = os.path.join(self.certificate_dir, f'results_{self.current_datetime}.html')
57
+ self.result_html_path = os.path.join(self.certificate_dir, f'results_{self.current_datetime.strftime('%Y%m%d_%H%M%S')}.html')
58
+ self.result_pdf_path = os.path.join(self.certificate_dir, f'results_{self.current_datetime.strftime('%Y%m%d_%H%M%S')}.pdf')
56
59
  self.template_engine = TemplateEngine()
57
60
  self.env = env
58
61
 
@@ -68,6 +71,7 @@ class GWCertificate:
68
71
  self.stress_pps = stress_pps
69
72
  self.aggregation_time = aggregation_time
70
73
  self.actions = actions
74
+ self.error = ""
71
75
 
72
76
  # UART-related. Require only when running tests that need it
73
77
  self.use_uart = not all(test in TESTS_NO_UART for test in tests)
@@ -76,7 +80,8 @@ class GWCertificate:
76
80
  self.uart_comports = get_uart_ports()
77
81
  debug_print(f'UART Ports:{self.uart_comports}')
78
82
  if len(self.uart_comports) < 1:
79
- raise GWCertificateError('A Wiliot certification kit must be connected to USB!')
83
+ self.error = "A Wiliot certification kit must be connected to USB!"
84
+ raise GWCertificateError(self.error)
80
85
 
81
86
  for port in self.uart_comports:
82
87
  try:
@@ -85,13 +90,18 @@ class GWCertificate:
85
90
  except UARTError as e:
86
91
  debug_print(f'Port: {port} - {e}')
87
92
  if type(self.uart) is not UARTInterface:
88
- raise GWCertificateError("Cannot initialize any port!")
93
+ self.error = "Cannot initialize any port!"
94
+ raise GWCertificateError(self.error)
89
95
  self.ble_sim = BLESimulator(self.uart)
90
96
  self.sniffer = BLESniffer(self.uart, logger_filepath=self.sniffer_logger_filepath)
91
97
 
92
98
  # Tests
93
99
  self.tests = [t(**self.__dict__) for t in tests]
94
100
  debug_print(f'Running Tests: {self.tests}')
101
+
102
+ def runtime(self):
103
+ datetime.timedelta
104
+ return datetime.datetime.now() - self.current_datetime
95
105
 
96
106
  def run_tests(self):
97
107
  debug_print("Sleeping 20 seconds after mqtt connect")
@@ -125,11 +135,13 @@ class GWCertificate:
125
135
  sniffer_log = sniffer_log,
126
136
  gw_id = self.gw_id,
127
137
  version = self.gw_cert_version,
128
- datetime = self.current_datetime)
138
+ datetime = self.current_datetime.strftime('%Y%m%d_%H%M%S'))
129
139
  with open(self.result_html_path, 'w', encoding="utf-8") as f:
130
140
  f.write(html)
141
+ cert_results.generate_pdf_results_file(self)
131
142
  debug_print("Test Finished. Results HTML Saved: " + self.result_html_path)
132
143
  webbrowser.open('file://' + os.path.realpath(self.result_html_path))
144
+ webbrowser.open('file://' + os.path.realpath(self.result_pdf_path))
133
145
 
134
146
  if __name__ == "__main__":
135
147
  from api_secrets import *
@@ -27,8 +27,8 @@ def filter_actions(actions_names):
27
27
  def main():
28
28
  usage = (
29
29
  "usage: wlt-gw-certificate [-h] -owner OWNER -gw GW\n"
30
- f" [-tests {{connection, uplink, downlink, stress}}] [-update] [-pps {STRESS_DEFAULT_PPS}]\n"
31
- " [-agg AGG] [-env {prod, test, dev}] [-no-reboot]"
30
+ f" [-tests {{connection, uplink, downlink, actions, stress}}] [-update] [-pps {STRESS_DEFAULT_PPS}]\n"
31
+ f" [-actions {{info, reboot, bridgeota}}] [-agg AGG] [-env {{prod, test, dev}}]"
32
32
  )
33
33
 
34
34
  parser = ArgumentParser(prog='wlt-gw-certificate',
@@ -43,7 +43,7 @@ def main():
43
43
  help="Tests to run. Registration omitted by default.", required=False, nargs='+',
44
44
  default=['connection', 'uplink', 'downlink', 'actions', 'stress'])
45
45
  optional.add_argument('-actions', type=str, choices=['info', 'reboot', 'bridgeota'],
46
- help="Action stages to run under ActionsTest", required=False, nargs='+', default=['info', 'reboot', 'ota'])
46
+ help="Action stages to run under ActionsTest", required=False, nargs='+', default=['info', 'reboot', 'bridgeota'])
47
47
  optional.add_argument('-update', action='store_true', help='Update test board firmware', default=False, required=False)
48
48
  optional.add_argument('-pps', type=int, help='Single packets-per-second rate to simulate in the stress test',
49
49
  choices=STRESS_DEFAULT_PPS, default=None, required=False)
@@ -216,6 +216,7 @@ class MqttClient:
216
216
  "gatewayId": gw_id,
217
217
  "imageDirUrl": image_dir_url,
218
218
  "versionUUID": version_uuid,
219
+ "upgradeBlSd": upgrade_bl_sd,
219
220
  "txPacket": reboot_packet,
220
221
  "txMaxRetries": tx_max_duration // 100,
221
222
  "txMaxDurationMs": tx_max_duration,
@@ -167,7 +167,7 @@ class UARTInterface:
167
167
  def check_fw_supported(self):
168
168
  hex_version = version.parse(os.path.splitext(os.path.basename(LATEST_VERSION_PATH))[0].split('_')[0])
169
169
  if self.fw_version >= hex_version:
170
- debug_print(f'GW Running version {self.fw_version}')
170
+ debug_print(f'Certification kit version {self.fw_version}')
171
171
  return True
172
172
  return False
173
173
 
@@ -128,7 +128,7 @@ class BridgeOTAStage(GenericActionsStage):
128
128
  def __init__(self, **kwargs):
129
129
  super().__init__(**kwargs, stage_name=type(self).__name__)
130
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"
131
+ self.error_summary = "Bridge wasn't upgraded."
132
132
  self.action = "Bridge Upgrade"
133
133
 
134
134
  OTA_VERSIONS_TO_USE = ("4.4.52", "4.4.53")
@@ -195,6 +195,7 @@ class BridgeOTAStage(GenericActionsStage):
195
195
 
196
196
  # Calculate whether stage pass/failed
197
197
  if self.action_status is None or self.status_code != 0:
198
+ debug_print("Failed to receive an actionStatus message.")
198
199
  self.stage_pass = MINIMUM_SCORE
199
200
  self.add_to_stage_report(f"The bridge OTA test failed")
200
201
  if self.action_status is None:
@@ -204,17 +205,22 @@ class BridgeOTAStage(GenericActionsStage):
204
205
  elif self.status_code != 0:
205
206
  self.add_to_stage_report(f"Uploaded actionStatus status value received is {self.status_code}.")
206
207
  if self.current_version == self.desired_version:
208
+ debug_print("Bridge was upgraded successfully")
209
+ self.error_summary = "Failed to receive actionStatus message."
207
210
  self.add_to_stage_report(f"Note that the bridge was actually upgraded successfully.")
211
+ self.add_to_stage_report(f"Reboot packet received {(self.reboot_packet_ts - self.start_time).total_seconds():.1f}s after start.")
208
212
  self.add_to_stage_report(f"{GW_BRIDGE_OTA_DOC}")
209
213
  else:
210
214
  if self.current_version == self.desired_version:
211
215
  self.stage_pass = PERFECT_SCORE
216
+ debug_print("Bridge was upgraded successfully, actionStatus message received")
212
217
  self.add_to_stage_report(f"Bridge was upgraded and an actionStatus message was received from the gateway.")
213
218
  self.add_to_stage_report(f"Action status received {(self.action_status_ts - self.start_time).total_seconds():.1f}s after start.")
214
219
  self.add_to_stage_report(f"Reboot packet received {(self.reboot_packet_ts - self.start_time).total_seconds():.1f}s after start.")
215
220
  self.add_to_stage_report(f"Action status received {(self.action_status_ts - self.reboot_packet_ts).total_seconds():.1f}s after reboot.")
216
221
  else:
217
222
  self.stage_pass = MINIMUM_SCORE
223
+ debug_print("Bridge failed to upgrade")
218
224
  self.add_to_stage_report(f"The bridge OTA test failed")
219
225
  self.add_to_stage_report(f"Uploaded actionStatus message indicated success although the bridge was not upgraded.")
220
226
 
@@ -248,7 +254,6 @@ class ActionsTest(GenericTest):
248
254
 
249
255
  def run(self):
250
256
  super().run()
251
- self.test_pass = PERFECT_SCORE
252
257
  for stage in self.stages:
253
258
  stage.prepare_stage()
254
259
  stage.run()
@@ -182,5 +182,5 @@ class ConnectionTest(GenericTest):
182
182
  for stage in self.stages:
183
183
  stage.prepare_stage()
184
184
  stage.run()
185
- self.test_pass = PassCriteria.calc_for_test(self, stage)
186
185
  self.add_to_test_report(stage.generate_stage_report())
186
+ self.test_pass = PassCriteria.calc_for_test(self, stage)
@@ -7,6 +7,7 @@ from gw_certificate.common.debug import debug_print
7
7
  from gw_certificate.api_if.gw_capabilities import GWCapabilities
8
8
  from gw_certificate.interface.ble_simulator import BLESimulator
9
9
  from gw_certificate.interface.mqtt import MqttClient
10
+ from gw_certificate.ag.ut_defines import TEST_PASSED, TEST_FAILED, TEST_INCONCLUSIVE, TEST_OPTIONAL, TEST_WARNING, TEST_INFO
10
11
 
11
12
  PASS_STATUS = {True: 'PASS', False: 'FAIL'}
12
13
 
@@ -37,19 +38,6 @@ class PassCriteria():
37
38
  return 'Inconclusive'
38
39
  else:
39
40
  return 'Fail'
40
-
41
- @staticmethod
42
- def missing_score(pass_value:int) -> int:
43
- return PERFECT_SCORE - pass_value
44
-
45
- @staticmethod
46
- def calc_for_stage_uplink(pass_value:int, stage_name:str) -> int:
47
- error_msg = "Insufficient amount of packets were scanned & uploaded by the gateway"
48
- return pass_value, error_msg
49
-
50
- @staticmethod
51
- def calc_for_stage_stress(pass_value: int, stage_name:str) -> int:
52
- return pass_value
53
41
 
54
42
  @staticmethod
55
43
  def calc_for_stage_downlink(rsquared, slope, stage_name:str):
@@ -99,12 +87,14 @@ class GenericTest:
99
87
  self.pass_min = PASS_MINIMUM
100
88
  self.inconclusive_min = INCONCLUSIVE_MINIMUM
101
89
  self.start_time = None
90
+ self.duration = None
102
91
  self.test_name = test_name
103
92
  self.test_dir = os.path.join(self.certificate_dir, self.test_name)
104
93
  self.env_dirs.create_dir(self.test_dir)
105
94
  self.stages = []
106
95
  self.test_tooltip = kwargs.get('test_tooltip', 'Missing tooltip')
107
96
  self.result_indication = kwargs.get('result_indication', SCORE_BASED)
97
+ self.rc = TEST_PASSED
108
98
 
109
99
  def __repr__(self):
110
100
  return self.test_name
@@ -125,8 +115,12 @@ class GenericTest:
125
115
  def create_test_html(self):
126
116
  self.report_html = self.template_engine.render_template('test.html', test=self,
127
117
  running_time = self.runtime())
128
-
118
+
129
119
  def end_test(self):
120
+ self.determine_rc()
121
+ for stage in self.stages:
122
+ stage.determine_rc()
123
+ self.duration = self.runtime()
130
124
  self.create_test_html()
131
125
 
132
126
  def score_pass(self):
@@ -143,6 +137,21 @@ class GenericTest:
143
137
  if self.test_pass < self.inconclusive_min:
144
138
  return True
145
139
  return False
140
+
141
+ def determine_rc(self):
142
+ # Set test rc - defaults to TEST_PASSED (rc=0)
143
+ if self.result_indication == 'info':
144
+ if self.score_pass():
145
+ self.rc = TEST_INFO
146
+ else:
147
+ self.rc = TEST_WARNING
148
+ elif self.result_indication == 'optional':
149
+ self.rc = TEST_OPTIONAL
150
+ else:
151
+ if self.score_inconclusive():
152
+ self.rc = TEST_INCONCLUSIVE
153
+ elif self.score_fail():
154
+ self.rc = TEST_FAILED
146
155
 
147
156
 
148
157
  class GenericStage():
@@ -156,9 +165,11 @@ class GenericStage():
156
165
  self.report = ''
157
166
  self.report_html = ''
158
167
  self.start_time = None
168
+ self.duration = None
159
169
  self.csv_path = os.path.join(self.test_dir, f'{self.stage_name}.csv')
160
170
  self.stage_tooltip = kwargs.get('stage_tooltip', 'Missing tooltip')
161
171
  self.error_summary = kwargs.get('error_summary', ERR_SUMMARY_DEFAULT)
172
+ self.rc = TEST_PASSED
162
173
 
163
174
  def __repr__(self):
164
175
  return self.stage_name
@@ -180,11 +191,14 @@ class GenericStage():
180
191
 
181
192
  def add_report_header(self):
182
193
  uncapitalize = lambda s: s[:1].lower() + s[1:] if s else ''
183
- self.add_to_stage_report(f'Stage run time: {datetime.datetime.now() - self.start_time}')
194
+ self.duration = datetime.datetime.now() - self.start_time
195
+ self.add_to_stage_report(f'Stage run time: {self.duration}')
184
196
  self.add_to_stage_report(f'This stage {uncapitalize(self.stage_tooltip)}.')
185
197
  self.add_report_line_separator()
186
198
 
187
199
  def add_report_topic_validation(self, topic:Literal['status', 'data']):
200
+ pass
201
+ # Pass until validated
188
202
  if self.topic_suffix != '':
189
203
  return
190
204
  valid_topic, invalid_msg, invalid_topic = self.mqttc.validate_serialization_topic(topic)
@@ -192,7 +206,7 @@ class GenericStage():
192
206
  # For now not failing stage since the customBroker command include topics explicitly
193
207
  # self.stage_pass = MINIMUM_SCORE
194
208
  # 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()}')
209
+ self.add_to_stage_report(f'Note: Received message on {invalid_topic} although serialization is {self.mqttc.get_serialization()}')
196
210
 
197
211
  def score_pass(self):
198
212
  if self.stage_pass >= self.pass_min:
@@ -208,4 +222,16 @@ class GenericStage():
208
222
  if self.stage_pass < self.inconclusive_min:
209
223
  return True
210
224
  return False
211
-
225
+
226
+ def determine_rc(self):
227
+ # Set stage rc - defaults to TEST_PASSED (rc=0)
228
+ if self.result_indication == 'info':
229
+ if self.score_pass():
230
+ self.rc = TEST_INFO
231
+ else:
232
+ self.rc = TEST_WARNING
233
+ else:
234
+ if self.score_inconclusive():
235
+ self.rc = TEST_INCONCLUSIVE
236
+ elif self.score_fail():
237
+ self.rc = TEST_FAILED
@@ -66,6 +66,7 @@ class GenericRegistrationStage(GenericStage):
66
66
  debug_print(f"Kick response:{response}")
67
67
 
68
68
  def validate_kong_logs(self, endpoint:Literal['device-authorize', 'registry', 'token', 'refresh']):
69
+ message = None
69
70
  try:
70
71
  message = self.edge.get_kong_logs(self.gw_id)
71
72
  except WiliotCloudError as wce:
@@ -78,7 +79,7 @@ class GenericRegistrationStage(GenericStage):
78
79
  return False
79
80
  elif status_code == None:
80
81
  raise wce
81
- if message.get('status_code') != 200:
82
+ if isinstance(message, dict) and message.get('status_code') != 200:
82
83
  debug_print(f"Failed fetching logs, status_code:{message.get('status_code')}")
83
84
  return False
84
85