wiliot-certificate 1.4.0a2__py3-none-any.whl → 1.5.0a1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- brg_certificate/ag/energous_v0_defines.py +12 -12
- brg_certificate/ag/energous_v1_defines.py +12 -12
- brg_certificate/ag/energous_v2_defines.py +12 -12
- brg_certificate/ag/energous_v3_defines.py +12 -12
- brg_certificate/ag/energous_v4_defines.py +12 -12
- brg_certificate/ag/fanstel_lan_v0_defines.py +12 -12
- brg_certificate/ag/fanstel_lte_v0_defines.py +12 -12
- brg_certificate/ag/fanstel_wifi_v0_defines.py +12 -12
- brg_certificate/ag/minew_lte_v0_defines.py +12 -12
- brg_certificate/ag/wlt_cmd_if.html +1 -1
- brg_certificate/ag/wlt_types.html +3 -3
- brg_certificate/ag/wlt_types_ag.py +12 -12
- brg_certificate/brg_certificate.py +9 -6
- brg_certificate/cert_common.py +21 -13
- brg_certificate/cert_config.py +1 -1
- brg_certificate/cert_defines.py +21 -3
- brg_certificate/cert_gw_sim.py +6 -4
- brg_certificate/cert_mqtt.py +8 -2
- brg_certificate/cert_prints.py +7 -5
- brg_certificate/cert_protobuf.py +5 -1
- brg_certificate/cert_results.py +99 -69
- brg_certificate/cert_utils.py +10 -14
- brg_certificate/restore_brg.py +2 -0
- brg_certificate/tests/calibration/interval_test/interval_test.py +1 -1
- brg_certificate/tests/calibration/output_power_test/output_power_test.py +1 -1
- brg_certificate/tests/calibration/pattern_test/pattern_test.py +1 -1
- brg_certificate/tests/datapath/adaptive_pacer_algo_test/adaptive_pacer_algo_test.py +4 -4
- brg_certificate/tests/datapath/num_of_tags_test/num_of_tags_test.py +2 -2
- brg_certificate/tests/datapath/output_power_test/output_power_test.py +1 -1
- brg_certificate/tests/datapath/pacer_interval_ble5_test/pacer_interval_ble5_test.py +1 -1
- brg_certificate/tests/datapath/pacer_interval_tags_count_test/pacer_interval_tags_count_test.py +2 -2
- brg_certificate/tests/datapath/pacer_interval_test/pacer_interval_test.py +1 -1
- brg_certificate/tests/datapath/pattern_test/pattern_test.py +1 -1
- brg_certificate/tests/datapath/pkt_filter_ble5_test/pkt_filter_ble5_test.py +1 -1
- brg_certificate/tests/datapath/pkt_filter_gen3_test/pkt_filter_gen3_test.py +1 -1
- brg_certificate/tests/datapath/pkt_filter_test/pkt_filter_test.py +1 -1
- brg_certificate/tests/datapath/rssi_threshold_test/rssi_threshold_test.py +1 -1
- brg_certificate/tests/datapath/rx_channel_test/rx_channel_test.py +1 -1
- brg_certificate/tests/datapath/rx_rate_gen2_test/rx_rate_gen2_test.py +1 -1
- brg_certificate/tests/datapath/rx_rate_gen3_test/rx_rate_gen3_test.py +1 -1
- brg_certificate/tests/datapath/stress_gen3_test/stress_gen3_test.py +2 -2
- brg_certificate/tests/datapath/stress_test/stress_test.py +2 -2
- brg_certificate/tests/datapath/tx_repetition_algo_test/tx_repetition_algo_test.py +1 -1
- brg_certificate/tests/datapath/tx_repetition_test/tx_repetition_test.py +1 -1
- brg_certificate/tests/edge_mgmt/actions_test/actions_test.py +4 -4
- brg_certificate/tests/edge_mgmt/brg2brg_ota_ble5_test/brg2brg_ota_ble5_test.py +1 -1
- brg_certificate/tests/edge_mgmt/brg2brg_ota_test/brg2brg_ota_test.py +1 -1
- brg_certificate/tests/edge_mgmt/leds_test/leds_test.py +1 -1
- brg_certificate/tests/edge_mgmt/ota_test/ota_test.py +1 -1
- brg_certificate/tests/edge_mgmt/stat_test/stat_test.py +1 -1
- brg_certificate/tests/energy2400/duty_cycle_test/duty_cycle_test.py +1 -1
- brg_certificate/tests/energy2400/output_power_test/output_power_test.py +1 -1
- brg_certificate/tests/energy2400/pattern_test/pattern_test.py +1 -1
- brg_certificate/tests/energy2400/signal_indicator_ble5_test/signal_indicator_ble5_test.py +1 -1
- brg_certificate/tests/energy2400/signal_indicator_sub1g_2_4_test/signal_indicator_sub1g_2_4_test.py +1 -1
- brg_certificate/tests/energy_sub1g/duty_cycle_test/duty_cycle_test.py +1 -1
- brg_certificate/tests/energy_sub1g/pattern_test/pattern_test.py +1 -1
- brg_certificate/tests/energy_sub1g/signal_indicator_functionality_test/signal_indicator_functionality_test.py +1 -1
- brg_certificate/tests/energy_sub1g/signal_indicator_test/signal_indicator_test.py +1 -1
- brg_certificate/wltPb_pb2.py +50 -38
- brg_certificate/wltPb_pb2.pyi +32 -32
- brg_certificate/wlt_types.py +4 -6
- common/wlt_logo.png +0 -0
- gw_certificate/ag/ut_defines.py +4 -1
- gw_certificate/cert_results.py +138 -0
- gw_certificate/gw_certificate.py +20 -6
- gw_certificate/interface/mqtt.py +1 -0
- gw_certificate/tests/actions.py +0 -1
- gw_certificate/tests/connection.py +1 -1
- gw_certificate/tests/generic.py +43 -17
- {wiliot_certificate-1.4.0a2.dist-info → wiliot_certificate-1.5.0a1.dist-info}/METADATA +6 -4
- {wiliot_certificate-1.4.0a2.dist-info → wiliot_certificate-1.5.0a1.dist-info}/RECORD +76 -74
- {wiliot_certificate-1.4.0a2.dist-info → wiliot_certificate-1.5.0a1.dist-info}/top_level.txt +1 -0
- {wiliot_certificate-1.4.0a2.dist-info → wiliot_certificate-1.5.0a1.dist-info}/LICENSE +0 -0
- {wiliot_certificate-1.4.0a2.dist-info → wiliot_certificate-1.5.0a1.dist-info}/WHEEL +0 -0
- {wiliot_certificate-1.4.0a2.dist-info → wiliot_certificate-1.5.0a1.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,138 @@
|
|
|
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
|
+
if gw_cert.error:
|
|
43
|
+
title = Paragraph(f"<b>Wiliot Gateway Certificate Error!</b>", red_header)
|
|
44
|
+
hdr_page.append(title)
|
|
45
|
+
hdr_page.append(Spacer(1, 20))
|
|
46
|
+
hdr_page.append(Paragraph(f"{gw_cert.error}", text_style_bold))
|
|
47
|
+
else:
|
|
48
|
+
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)
|
|
49
|
+
hdr_page.append(title)
|
|
50
|
+
hdr_page.append(Spacer(1, 20))
|
|
51
|
+
hdr_page.append(Paragraph(f"<b>Summary</b>", module_header))
|
|
52
|
+
hdr_page.append(Spacer(1, 20))
|
|
53
|
+
hdr_page.append(Paragraph(f"Run date: {gw_cert.current_datetime.strftime('%d/%m/%Y, %H:%M:%S')}", text_style_bold))
|
|
54
|
+
hdr_page.append(Paragraph(f"Tests duration: {format_timedelta(gw_cert.runtime())}", text_style_bold))
|
|
55
|
+
hdr_page.append(Paragraph(f"Certificate version: {gw_cert.gw_cert_version}", text_style_bold))
|
|
56
|
+
hdr_page.append(Paragraph(f"BLE simulator mac: {gw_cert.uart.mac}", text_style_bold))
|
|
57
|
+
hdr_page.append(Paragraph(f"BLE simulator version: {gw_cert.uart.fw_version}", text_style_bold))
|
|
58
|
+
hdr_page.append(Paragraph(f"Tested gateway ID: {gw_cert.gw_id}", text_style_bold))
|
|
59
|
+
hdr_page.append(Spacer(1, 20))
|
|
60
|
+
|
|
61
|
+
# Count Table
|
|
62
|
+
count_data = [
|
|
63
|
+
["PASSED", "INCONCLUSIVE", "FAILED", "TOTAL"],
|
|
64
|
+
[len(gw_cert.tests)-(failures+inconclusive), inconclusive, failures, len(gw_cert.tests)]
|
|
65
|
+
]
|
|
66
|
+
count_table = Table(count_data)
|
|
67
|
+
count_table.setStyle(INNER_TABLE_STYLE)
|
|
68
|
+
hdr_page.append(count_table)
|
|
69
|
+
hdr_page.append(Spacer(1, 20))
|
|
70
|
+
|
|
71
|
+
# Test Results
|
|
72
|
+
summary_data = []
|
|
73
|
+
text_style_center = STYLES_PDF.get("BLACK", ParagraphStyle("Default"))
|
|
74
|
+
text_style_left = STYLES_PDF.get("BLACK_LEFT", ParagraphStyle("Default"))
|
|
75
|
+
for test in gw_cert.tests:
|
|
76
|
+
summary_data += [[test, pass_or_fail_pdf(test), format_timedelta(test.duration)]]
|
|
77
|
+
elements.append(Paragraph(f"<b>{test.test_name}</b>", module_header))
|
|
78
|
+
elements.append(Spacer(1, 20))
|
|
79
|
+
elements.append(pass_or_fail_pdf(test))
|
|
80
|
+
elements.append(Spacer(1, 10))
|
|
81
|
+
elements.append(Paragraph(f"Test duration: {format_timedelta(test.duration)}", text_style_bold))
|
|
82
|
+
elements.append(Spacer(1, 10))
|
|
83
|
+
inner_table, stages_breakdown = [["Phase", "Result", "Duration"]], []
|
|
84
|
+
for stage in test.stages:
|
|
85
|
+
stages_breakdown += [KeepTogether([Paragraph(stage.stage_name, test_header), Spacer(1, 10), pass_or_fail_pdf(stage), Spacer(1, 10)]
|
|
86
|
+
+ [Paragraph(l, text_style_left) for l in stage.report.split('\n')]
|
|
87
|
+
+ [Spacer(1, 10)])]
|
|
88
|
+
inner_table += [[Paragraph(stage.stage_name, text_style_center), pass_or_fail_pdf(stage), Paragraph(format_timedelta(stage.duration), text_style_center)]]
|
|
89
|
+
test_table = Table(inner_table)
|
|
90
|
+
test_table.setStyle(INNER_TABLE_STYLE)
|
|
91
|
+
elements.append(test_table)
|
|
92
|
+
elements.append(Spacer(1, 20))
|
|
93
|
+
elements += stages_breakdown
|
|
94
|
+
elements.append(PageBreak())
|
|
95
|
+
summary_table = Table([["Name", "Result", "Duration"]] + summary_data)
|
|
96
|
+
summary_table.setStyle(INNER_TABLE_STYLE)
|
|
97
|
+
elements = hdr_page + [summary_table, PageBreak()] + elements
|
|
98
|
+
|
|
99
|
+
doc.build(elements)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
##################################
|
|
103
|
+
# PDF
|
|
104
|
+
##################################
|
|
105
|
+
STYLES_PDF = {
|
|
106
|
+
"GREEN_HEADER": ParagraphStyle("Green Header", fontName="Helvetica-Bold", fontSize=20, textColor=colors.green, alignment=TA_CENTER),
|
|
107
|
+
"RED_HEADER": ParagraphStyle("Red Header", fontName="Helvetica-Bold", fontSize=20, textColor=colors.red, alignment=TA_CENTER),
|
|
108
|
+
"MODULE_HEADER": ParagraphStyle("Module Header", fontName="Helvetica-Bold", fontSize=16, textColor=colors.navy, alignment=TA_CENTER),
|
|
109
|
+
"TEST_HEADER": ParagraphStyle("Test Header", fontName="Helvetica-Bold", fontSize=12, textColor=colors.black, alignment=TA_CENTER),
|
|
110
|
+
"BLACK": ParagraphStyle("Black", fontName="Helvetica", fontSize=9, textColor=colors.black, splitLongWords=False, alignment=TA_CENTER, wordWrap = 'CJK'),
|
|
111
|
+
"BLACK_LEFT": ParagraphStyle("Black Left", fontName="Helvetica", fontSize=9, textColor=colors.black, splitLongWords=False, alignment=TA_LEFT, wordWrap = 'CJK'),
|
|
112
|
+
"BLACK_BOLD": ParagraphStyle("Black Bold", fontName="Helvetica-Bold", fontSize=9, textColor=colors.black, splitLongWords=False, alignment=TA_LEFT, wordWrap = 'CJK'),
|
|
113
|
+
"BLUE": ParagraphStyle("Blue", fontName="Helvetica-Bold", fontSize=9, textColor=colors.navy, splitLongWords=False, alignment=TA_CENTER),
|
|
114
|
+
"CYAN": ParagraphStyle("Cyan", fontName="Helvetica-Bold", fontSize=9, textColor=colors.cyan, splitLongWords=False, alignment=TA_CENTER),
|
|
115
|
+
"GREEN": ParagraphStyle("Green", fontName="Helvetica-Bold", fontSize=9, textColor=colors.green, splitLongWords=False, alignment=TA_CENTER),
|
|
116
|
+
"WARNING": ParagraphStyle("Warning", fontName="Helvetica-Bold", fontSize=9, textColor=colors.gold, splitLongWords=False, alignment=TA_CENTER),
|
|
117
|
+
"RED": ParagraphStyle("Red", fontName="Helvetica-Bold", fontSize=9, textColor=colors.red, splitLongWords=False, alignment=TA_CENTER),
|
|
118
|
+
"GRAY": ParagraphStyle("Gray", fontName="Helvetica-Bold", fontSize=9, textColor=colors.gray, splitLongWords=False, alignment=TA_CENTER),
|
|
119
|
+
}
|
|
120
|
+
def color_pdf(c, t):
|
|
121
|
+
style = STYLES_PDF.get(c, ParagraphStyle("Default"))
|
|
122
|
+
return Paragraph(t, style)
|
|
123
|
+
pdf_result_map = {TEST_FAILED: color_pdf("RED", "FAILED"), TEST_INCONCLUSIVE: color_pdf("WARNING", "INCONCLUSIVE"),
|
|
124
|
+
TEST_PASSED: color_pdf("GREEN", "PASSED"), TEST_INFO: color_pdf("CYAN", "INFO"),
|
|
125
|
+
TEST_WARNING: color_pdf("WARNING", "WARNING"), TEST_OPTIONAL: color_pdf("GRAY", "OPTIONAL")}
|
|
126
|
+
pass_or_fail_pdf = lambda obj : pdf_result_map[obj.rc]
|
|
127
|
+
|
|
128
|
+
INNER_TABLE_STYLE = TableStyle([
|
|
129
|
+
('BACKGROUND', (0, 0), (-1, 0), colors.grey),
|
|
130
|
+
('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
|
|
131
|
+
('ALIGN', (0, 0), (-1, -1), 'CENTER'),
|
|
132
|
+
('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
|
|
133
|
+
('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
|
|
134
|
+
('FONTSIZE', (0, 0), (-1, 0), 9),
|
|
135
|
+
('BOTTOMPADDING', (0, 0), (-1, 0), 12),
|
|
136
|
+
('BACKGROUND', (0, 1), (-1, -1), colors.whitesmoke),
|
|
137
|
+
('WORDWRAP', (0, 0), (-1, -1), False),
|
|
138
|
+
])
|
gw_certificate/gw_certificate.py
CHANGED
|
@@ -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()
|
|
49
|
-
self.
|
|
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,9 @@ 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
|
-
|
|
83
|
+
self.error = "A Wiliot certification kit must be connected to USB!"
|
|
84
|
+
cert_results.generate_pdf_results_file(self)
|
|
85
|
+
raise GWCertificateError(self.error)
|
|
80
86
|
|
|
81
87
|
for port in self.uart_comports:
|
|
82
88
|
try:
|
|
@@ -85,13 +91,19 @@ class GWCertificate:
|
|
|
85
91
|
except UARTError as e:
|
|
86
92
|
debug_print(f'Port: {port} - {e}')
|
|
87
93
|
if type(self.uart) is not UARTInterface:
|
|
88
|
-
|
|
94
|
+
self.error = "Cannot initialize any port!"
|
|
95
|
+
cert_results.generate_pdf_results_file(self)
|
|
96
|
+
raise GWCertificateError(self.error)
|
|
89
97
|
self.ble_sim = BLESimulator(self.uart)
|
|
90
98
|
self.sniffer = BLESniffer(self.uart, logger_filepath=self.sniffer_logger_filepath)
|
|
91
99
|
|
|
92
100
|
# Tests
|
|
93
101
|
self.tests = [t(**self.__dict__) for t in tests]
|
|
94
102
|
debug_print(f'Running Tests: {self.tests}')
|
|
103
|
+
|
|
104
|
+
def runtime(self):
|
|
105
|
+
datetime.timedelta
|
|
106
|
+
return datetime.datetime.now() - self.current_datetime
|
|
95
107
|
|
|
96
108
|
def run_tests(self):
|
|
97
109
|
debug_print("Sleeping 20 seconds after mqtt connect")
|
|
@@ -125,11 +137,13 @@ class GWCertificate:
|
|
|
125
137
|
sniffer_log = sniffer_log,
|
|
126
138
|
gw_id = self.gw_id,
|
|
127
139
|
version = self.gw_cert_version,
|
|
128
|
-
datetime = self.current_datetime)
|
|
140
|
+
datetime = self.current_datetime.strftime('%Y%m%d_%H%M%S'))
|
|
129
141
|
with open(self.result_html_path, 'w', encoding="utf-8") as f:
|
|
130
142
|
f.write(html)
|
|
143
|
+
cert_results.generate_pdf_results_file(self)
|
|
131
144
|
debug_print("Test Finished. Results HTML Saved: " + self.result_html_path)
|
|
132
145
|
webbrowser.open('file://' + os.path.realpath(self.result_html_path))
|
|
146
|
+
webbrowser.open('file://' + os.path.realpath(self.result_pdf_path))
|
|
133
147
|
|
|
134
148
|
if __name__ == "__main__":
|
|
135
149
|
from api_secrets import *
|
gw_certificate/interface/mqtt.py
CHANGED
|
@@ -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,
|
gw_certificate/tests/actions.py
CHANGED
|
@@ -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)
|
gw_certificate/tests/generic.py
CHANGED
|
@@ -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.
|
|
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'
|
|
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
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: wiliot_certificate
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.5.0a1
|
|
4
4
|
Summary: A library for certifying Wiliot-compliant boards
|
|
5
5
|
Author-email: Wiliot <support@wiliot.com>
|
|
6
6
|
License: MIT License
|
|
@@ -93,11 +93,13 @@ Increments time delays between packets to evaluate GW's capability in handling i
|
|
|
93
93
|
#### GW Certificate Release Notes:
|
|
94
94
|
1.4.0:
|
|
95
95
|
- Released in a standalone wiliot-certificate package
|
|
96
|
-
- Python 3.
|
|
96
|
+
- Python 3.13 support
|
|
97
97
|
- Gw API version 205 support
|
|
98
|
-
- Registration
|
|
98
|
+
- Registration test added
|
|
99
|
+
- Bridge OTA stage added under actions
|
|
99
100
|
- Aggregation flag supported by StressTest
|
|
100
|
-
|
|
101
|
+
- -update flag compatibility fix. Upgrades bootloader as well
|
|
102
|
+
- -actions flag to select specific actions to test
|
|
101
103
|
|
|
102
104
|
```
|
|
103
105
|
usage: wlt-gw-certificate [-h] -owner OWNER -gw GW [-suffix SUFFIX] [-tests {connection,uplink,downlink,stress}]
|