wiliot-certificate 4.5.0a2__py3-none-any.whl → 4.5.0a3__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.
- certificate/cert_common.py +2 -2
- certificate/cert_config.py +3 -3
- certificate/certificate_eth_test_list.txt +3 -2
- certificate/certificate_sanity_test_list.txt +3 -2
- certificate/certificate_test_list.txt +3 -3
- certificate/tests/cloud_connectivity/downlink_test/downlink_test.py +1 -4
- certificate/tests/datapath/event_ble5_test/event_ble5_test.py +6 -4
- certificate/tests/datapath/event_test/event_test.py +4 -3
- certificate/tests/datapath/pacer_interval_ble5_test/pacer_interval_ble5_test.py +4 -4
- certificate/tests/datapath/pkt_filter_ble5_chl21_test/pkt_filter_ble5_chl21_test.py +5 -5
- certificate/tests/datapath/pkt_filter_ble5_test/pkt_filter_ble5_test.py +5 -5
- certificate/tests/datapath/pkt_filter_brg2gw_ext_adv_test/pkt_filter_brg2gw_ext_adv_test.py +10 -8
- certificate/tests/energy2400/signal_indicator_ble5_test/signal_indicator_ble5_test.py +1 -2
- certificate/tests/energy2400/signal_indicator_ext_adv_test/signal_indicator_ext_adv_test.json +8 -9
- certificate/tests/energy2400/signal_indicator_ext_adv_test/signal_indicator_ext_adv_test.py +110 -270
- certificate/tests/sensors/ext_sensor_test/ext_sensor_test.py +4 -9
- common/web/templates/generator.html +141 -79
- common/web/web_utils.py +78 -56
- gui_certificate/server.py +111 -19
- gui_certificate/templates/cert_run.html +43 -6
- {wiliot_certificate-4.5.0a2.dist-info → wiliot_certificate-4.5.0a3.dist-info}/METADATA +4 -9
- {wiliot_certificate-4.5.0a2.dist-info → wiliot_certificate-4.5.0a3.dist-info}/RECORD +26 -26
- {wiliot_certificate-4.5.0a2.dist-info → wiliot_certificate-4.5.0a3.dist-info}/WHEEL +0 -0
- {wiliot_certificate-4.5.0a2.dist-info → wiliot_certificate-4.5.0a3.dist-info}/entry_points.txt +0 -0
- {wiliot_certificate-4.5.0a2.dist-info → wiliot_certificate-4.5.0a3.dist-info}/licenses/LICENSE +0 -0
- {wiliot_certificate-4.5.0a2.dist-info → wiliot_certificate-4.5.0a3.dist-info}/top_level.txt +0 -0
|
@@ -21,24 +21,53 @@
|
|
|
21
21
|
<h1 style="color:#00AB83">{{ title }}</h1>
|
|
22
22
|
<hr>
|
|
23
23
|
<form class="form-horizontal" id="form" action="">
|
|
24
|
+
<div class="row mb-3">
|
|
25
|
+
<div class="col-md-6">
|
|
26
|
+
<label for="filter_category" class="form-label"><strong>Filter by Type:</strong></label>
|
|
27
|
+
<select class="form-select" id="filter_category" name="filter_category" onchange="applyFilters()">
|
|
28
|
+
<option value="">All Types</option>
|
|
29
|
+
{% for cat in categories %}
|
|
30
|
+
<option value="{{ cat }}" {% if cat == filter_category or (not filter_category and cat == 'Module') %}selected{% endif %}>{{ cat }}</option>
|
|
31
|
+
{% endfor %}
|
|
32
|
+
</select>
|
|
33
|
+
</div>
|
|
34
|
+
<div class="col-md-6">
|
|
35
|
+
<label for="filter_version" class="form-label"><strong>Filter by API Version:</strong></label>
|
|
36
|
+
<select class="form-select" id="filter_version" name="filter_version" onchange="applyFilters()">
|
|
37
|
+
<option value="">All Versions</option>
|
|
38
|
+
{% for ver in api_versions %}
|
|
39
|
+
<option value="{{ ver }}" {% if ver == filter_version or (not filter_version and ver|int == API_VERSION_LATEST) %}selected{% endif %}>V{{ ver }}</option>
|
|
40
|
+
{% endfor %}
|
|
41
|
+
</select>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
<hr>
|
|
24
45
|
<div id="builder_form">
|
|
25
46
|
{% for n in pkt_types_list %}
|
|
26
|
-
<div class="form-check form-check-inline"
|
|
27
|
-
|
|
28
|
-
|
|
47
|
+
<div class="form-check form-check-inline pkt-radio"
|
|
48
|
+
data-category="{{ pkt_metadata.get(n, {}).get('category', 'Other') }}"
|
|
49
|
+
data-version="{{ pkt_metadata.get(n, {}).get('api_version', '') }}">
|
|
50
|
+
<input class="form-check-input" type="radio" name="radios" value="{{ n }}" id="radio_{{ n }}"
|
|
51
|
+
{% if n == wanted_pkt_type %}checked{% endif %} onclick="show();">
|
|
52
|
+
<label class="form-check-label" for="radio_{{ n }}">{{ n }}</label>
|
|
29
53
|
</div>
|
|
30
54
|
{% endfor %}
|
|
31
55
|
{% for n,p in pkt_types.items() %}
|
|
32
|
-
<div id="{{ n }}_form">
|
|
56
|
+
<div id="{{ n }}_form" style="display: none;">
|
|
33
57
|
<hr>
|
|
34
58
|
{% for k,v in p.__dict__.items() %}
|
|
35
59
|
<div class="row">
|
|
36
60
|
<label for="{{ n }}_{{ k }}" class="col-sm-2">{{ k }}:</label>
|
|
37
|
-
{%
|
|
38
|
-
|
|
61
|
+
{% set field_name = n + '_' + k %}
|
|
62
|
+
{% set saved_value = form_values.get(field_name, '') %}
|
|
63
|
+
{% if saved_value %}
|
|
64
|
+
{% set display_value = saved_value %}
|
|
65
|
+
{% elif k == 'brg_mac' or k == 'pkt_size' or k == 'ad_type' or k == 'uuid_msb' or k == 'uuid_lsb' or k == 'group_id' %}
|
|
66
|
+
{% set display_value = '0x' + ('%0x' % v).upper() %}
|
|
39
67
|
{% else %}
|
|
40
|
-
|
|
68
|
+
{% set display_value = v %}
|
|
41
69
|
{% endif %}
|
|
70
|
+
<input type="text" class="col-sm-4" name="{{ n }}_{{ k }}" value="{{ display_value }}">
|
|
42
71
|
</div>
|
|
43
72
|
{% endfor %}
|
|
44
73
|
</div>
|
|
@@ -63,86 +92,119 @@
|
|
|
63
92
|
<br>
|
|
64
93
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
|
|
65
94
|
<script>
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
const
|
|
70
|
-
const
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
var pktTypes = {{ pkt_types_list | tojson | safe }};
|
|
81
|
-
console.log(pktTypes)
|
|
82
|
-
var forms = [];
|
|
83
|
-
|
|
84
|
-
for (var i = 0; i < pktTypes.length; i++) {
|
|
85
|
-
forms[i] = document.getElementById(pktTypes[i]+"_form");
|
|
86
|
-
if (pktTypes[i] != "Hdr"){
|
|
87
|
-
forms[i].style.display = 'none';
|
|
95
|
+
var pktMetadata = {{ pkt_metadata | tojson | safe }};
|
|
96
|
+
|
|
97
|
+
function applyFilters() {
|
|
98
|
+
const categoryFilter = document.getElementById('filter_category').value;
|
|
99
|
+
const versionFilter = document.getElementById('filter_version').value;
|
|
100
|
+
const radioContainers = document.querySelectorAll('.pkt-radio');
|
|
101
|
+
radioContainers.forEach(function(container) {
|
|
102
|
+
const category = container.getAttribute('data-category');
|
|
103
|
+
const version = container.getAttribute('data-version');
|
|
104
|
+
const radio = container.querySelector('input[type="radio"]');
|
|
105
|
+
let show = true;
|
|
106
|
+
// Filter by category
|
|
107
|
+
if (categoryFilter && category !== categoryFilter) {
|
|
108
|
+
show = false;
|
|
88
109
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
radios[i].onclick = function() {
|
|
93
|
-
for(var j = 0; j < radios.length; j++) {
|
|
94
|
-
forms[j].style.display = 'none';
|
|
110
|
+
// Filter by version
|
|
111
|
+
if (versionFilter && version !== versionFilter) {
|
|
112
|
+
show = false;
|
|
95
113
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
else{
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
if (
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
else if (this.value.includes("Gw2Brg")){
|
|
106
|
-
default_value = group_id_gw2brg;
|
|
107
|
-
}
|
|
108
|
-
else if (this.value.includes("SignalIndicator")){
|
|
109
|
-
default_value = group_id_signal_indicator;
|
|
110
|
-
}
|
|
111
|
-
else if (this.value.includes("SideInfoSensor")){
|
|
112
|
-
default_value = group_id_side_info_sensor;
|
|
113
|
-
}
|
|
114
|
-
else if (this.value.includes("SideInfo")){
|
|
115
|
-
default_value = group_id_side_info;
|
|
116
|
-
}
|
|
117
|
-
else if (this.value.includes("Unified")){
|
|
118
|
-
if (this.value.includes("V0")){
|
|
119
|
-
if (this.value.includes("Ext")){
|
|
120
|
-
default_value = group_id_unified_ext_v0
|
|
121
|
-
}
|
|
122
|
-
else {
|
|
123
|
-
default_value = group_id_unified_v0
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
else if (this.value.includes("V1")){
|
|
127
|
-
if (this.value.includes("Ext")){
|
|
128
|
-
default_value = group_id_unified_ext_v1
|
|
129
|
-
}
|
|
130
|
-
else {
|
|
131
|
-
default_value = group_id_unified_v1
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
else if (this.value.includes("V2")){
|
|
135
|
-
default_value = group_id_unified_v2
|
|
136
|
-
}
|
|
114
|
+
// Show/hide the container
|
|
115
|
+
if (show) {
|
|
116
|
+
container.style.display = 'inline-block';
|
|
117
|
+
} else {
|
|
118
|
+
container.style.display = 'none';
|
|
119
|
+
// Uncheck if hidden
|
|
120
|
+
if (radio.checked) {
|
|
121
|
+
radio.checked = false;
|
|
137
122
|
}
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const form = document.getElementById('form');
|
|
128
|
+
const group_id_brg2gw = {{ GROUP_ID_BRG2GW }};
|
|
129
|
+
const group_id_gw2brg = {{ GROUP_ID_GW2BRG }};
|
|
130
|
+
const group_id_side_info_sensor = {{ GROUP_ID_SIDE_INFO_SENSOR }};
|
|
131
|
+
const group_id_side_info = {{ GROUP_ID_SIDE_INFO }};
|
|
132
|
+
const group_id_signal_indicator = {{ GROUP_ID_SIGNAL_INDICATOR }};
|
|
133
|
+
const group_id_unified_v0 = {{ GROUP_ID_UNIFIED_PKT_V0 }};
|
|
134
|
+
const group_id_unified_v1 = {{ GROUP_ID_UNIFIED_PKT_V1 }};
|
|
135
|
+
const group_id_unified_v2 = {{ GROUP_ID_UNIFIED_PKT_V2 }};
|
|
136
|
+
const group_id_unified_ext_v0 = {{ GROUP_ID_BLE5_EXTENDED_V0 }};
|
|
137
|
+
const group_id_unified_ext_v1 = {{ GROUP_ID_BLE5_EXTENDED_V1 }};
|
|
138
|
+
var pktTypes = {{ pkt_types_list | tojson | safe }};
|
|
139
|
+
|
|
140
|
+
function showPktForm(pktType) {
|
|
141
|
+
// Hide all packet forms
|
|
142
|
+
pktTypes.forEach(function(type) {
|
|
143
|
+
var formEl = document.getElementById(type + "_form");
|
|
144
|
+
if (formEl) formEl.style.display = 'none';
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// Show appropriate header and packet form
|
|
148
|
+
if (pktType && pktType.includes("Unified")) {
|
|
149
|
+
document.getElementById("Hdr_form").style.display = 'none';
|
|
150
|
+
document.getElementById("DataHdr_form").style.display = 'block';
|
|
151
|
+
var default_value = 0;
|
|
152
|
+
if (pktType.includes("V0")) {
|
|
153
|
+
default_value = pktType.includes("Ext") ? group_id_unified_ext_v0 : group_id_unified_v0;
|
|
154
|
+
} else if (pktType.includes("V1")) {
|
|
155
|
+
default_value = pktType.includes("Ext") ? group_id_unified_ext_v1 : group_id_unified_v1;
|
|
156
|
+
} else if (pktType.includes("V2")) {
|
|
157
|
+
default_value = group_id_unified_v2;
|
|
158
|
+
}
|
|
159
|
+
if (form.elements.DataHdr_group_id_major) {
|
|
160
|
+
form.elements.DataHdr_group_id_major.value = "0x" + default_value.toString(16).toUpperCase();
|
|
161
|
+
}
|
|
162
|
+
} else {
|
|
163
|
+
document.getElementById("Hdr_form").style.display = 'block';
|
|
164
|
+
document.getElementById("DataHdr_form").style.display = 'none';
|
|
165
|
+
var default_value = 0;
|
|
166
|
+
if (pktType && pktType.includes("Brg2Gw")) {
|
|
167
|
+
default_value = group_id_brg2gw;
|
|
168
|
+
} else if (pktType && pktType.includes("Gw2Brg")) {
|
|
169
|
+
default_value = group_id_gw2brg;
|
|
170
|
+
} else if (pktType && pktType.includes("SignalIndicator")) {
|
|
171
|
+
default_value = group_id_signal_indicator;
|
|
172
|
+
} else if (pktType && pktType.includes("SideInfoSensor")) {
|
|
173
|
+
default_value = group_id_side_info_sensor;
|
|
174
|
+
} else if (pktType && pktType.includes("SideInfo")) {
|
|
175
|
+
default_value = group_id_side_info;
|
|
176
|
+
}
|
|
177
|
+
if (form.elements.Hdr_group_id) {
|
|
138
178
|
form.elements.Hdr_group_id.value = "0x" + default_value.toString(16).toUpperCase();
|
|
139
179
|
}
|
|
140
|
-
console.log(this.value)
|
|
141
|
-
document.getElementById(this.value + "_form").style.display = 'block';
|
|
142
180
|
}
|
|
181
|
+
|
|
182
|
+
// Show the selected packet form
|
|
183
|
+
if (pktType) {
|
|
184
|
+
var pktForm = document.getElementById(pktType + "_form");
|
|
185
|
+
if (pktForm) pktForm.style.display = 'block';
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function show() {
|
|
190
|
+
// Set up click handlers
|
|
191
|
+
var radios = document.getElementsByName("radios");
|
|
192
|
+
for (var i = 0; i < radios.length; i++) {
|
|
193
|
+
radios[i].onclick = function() {
|
|
194
|
+
showPktForm(this.value);
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Show form for checked radio (if any)
|
|
199
|
+
for (var i = 0; i < radios.length; i++) {
|
|
200
|
+
if (radios[i].checked) {
|
|
201
|
+
showPktForm(radios[i].value);
|
|
202
|
+
break;
|
|
203
|
+
}
|
|
143
204
|
}
|
|
144
205
|
}
|
|
145
|
-
|
|
206
|
+
applyFilters(); // Apply filters on page load
|
|
207
|
+
show(); // Initialize form display (will show selected packet form if one is checked)
|
|
146
208
|
</script>
|
|
147
209
|
</body>
|
|
148
210
|
</html>
|
common/web/web_utils.py
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
from flask import render_template, request
|
|
3
|
-
import inspect
|
|
4
3
|
import argparse
|
|
5
4
|
import json
|
|
6
5
|
import re
|
|
@@ -28,7 +27,7 @@ FDM = "FDM"
|
|
|
28
27
|
CERT_WEB = "CERTIFICATE WEB"
|
|
29
28
|
|
|
30
29
|
# Defines to update jinja_env globals
|
|
31
|
-
GLOBAL_DEFINES_TO_UPDATE = {k:v for k,v in ag.__dict__.items() if 'GROUP_ID' in k}
|
|
30
|
+
GLOBAL_DEFINES_TO_UPDATE = {k:v for k,v in ag.__dict__.items() if 'GROUP_ID' in k or 'API_VERSION_LATEST' in k}
|
|
32
31
|
|
|
33
32
|
TestSchema = Dict[str, Any]
|
|
34
33
|
ModuleSchema = Dict[str, Any]
|
|
@@ -63,46 +62,90 @@ def utils_parser(app):
|
|
|
63
62
|
def utils_generator(app):
|
|
64
63
|
title = "Packet Generator"
|
|
65
64
|
output = ""
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
65
|
+
def parse_int_input(x, default=0):
|
|
66
|
+
x = str(x).strip()
|
|
67
|
+
if x.startswith('0x') or x.startswith('0X'):
|
|
68
|
+
return int(x, 16)
|
|
69
|
+
try:
|
|
70
|
+
return int(x)
|
|
71
|
+
except ValueError:
|
|
72
|
+
return default
|
|
73
|
+
|
|
74
|
+
def build_and_dump_pkt(pkt_type):
|
|
75
|
+
pkt_template = getattr(ag, pkt_type)()
|
|
76
|
+
pkt_params = {
|
|
77
|
+
k: parse_int_input(request.args.get(f"{pkt_type}_{k}"), pkt_template.__dict__.get(k, 0))
|
|
78
|
+
for k in pkt_template.__dict__.keys()
|
|
79
|
+
}
|
|
80
|
+
pkt = getattr(ag, pkt_type)(**pkt_params)
|
|
81
|
+
try:
|
|
82
|
+
return pkt.dump()
|
|
83
|
+
except Exception as e:
|
|
84
|
+
return f"<br>Error encoding {pkt_type} (bit structure error): {str(e)}<br>"
|
|
85
|
+
|
|
86
|
+
# Build packet types dictionary
|
|
87
|
+
dont_generate_strs = ["Cfg", "SideInfo"]
|
|
69
88
|
wlt_pkt_types = {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
89
|
+
'Hdr': ag.Hdr(),
|
|
90
|
+
'DataHdr': ag.DataHdr(),
|
|
91
|
+
**{cls.__name__: cls() for cls in ag.WLT_PKT_TYPES if not any([dg in cls.__name__ for dg in dont_generate_strs])}
|
|
73
92
|
}
|
|
74
|
-
# Find selected pkt type
|
|
75
|
-
for name ,p in wlt_pkt_types.items():
|
|
76
|
-
if name == wanted_pkt_type:
|
|
77
|
-
pkt = p
|
|
78
|
-
break
|
|
79
93
|
|
|
80
|
-
#
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
if
|
|
86
|
-
|
|
94
|
+
# Categorize packets and extract API versions
|
|
95
|
+
import re
|
|
96
|
+
pkt_metadata = {}
|
|
97
|
+
for pkt_name in list(wlt_pkt_types.keys())[2:]: # Skip Hdr and DataHdr
|
|
98
|
+
# Determine category
|
|
99
|
+
if pkt_name.startswith('Unified'):
|
|
100
|
+
category = 'Unified'
|
|
101
|
+
elif pkt_name.startswith('Module'):
|
|
102
|
+
category = 'Module'
|
|
103
|
+
elif pkt_name.startswith('Action'):
|
|
104
|
+
category = 'Action'
|
|
105
|
+
elif pkt_name.startswith('Brg2Brg'):
|
|
106
|
+
category = 'Brg2Brg'
|
|
107
|
+
elif pkt_name.startswith('Brg2Gw'):
|
|
108
|
+
category = 'Brg2Gw'
|
|
109
|
+
elif pkt_name.startswith('Sensor'):
|
|
110
|
+
category = 'Sensor'
|
|
87
111
|
else:
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
112
|
+
category = 'Other'
|
|
113
|
+
|
|
114
|
+
# Extract API version
|
|
115
|
+
version_match = re.search(r'V(\d+)$', pkt_name)
|
|
116
|
+
api_version = version_match.group(1) if version_match else None
|
|
117
|
+
|
|
118
|
+
pkt_metadata[pkt_name] = {
|
|
119
|
+
'category': category,
|
|
120
|
+
'api_version': api_version
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
# Get unique categories and API versions for filters
|
|
124
|
+
categories = sorted(set(m['category'] for m in pkt_metadata.values()))
|
|
125
|
+
api_versions = sorted(set(m['api_version'] for m in pkt_metadata.values() if m['api_version']),
|
|
126
|
+
key=lambda x: int(x) if x else 0, reverse=True)
|
|
127
|
+
|
|
128
|
+
wanted_pkt_type = request.args.get('radios')
|
|
129
|
+
if wanted_pkt_type:
|
|
130
|
+
# Determine header type and build header
|
|
131
|
+
hdr_type = 'DataHdr' if 'Unified' in wanted_pkt_type else 'Hdr'
|
|
132
|
+
output += build_and_dump_pkt(hdr_type)
|
|
133
|
+
output += build_and_dump_pkt(wanted_pkt_type)
|
|
134
|
+
|
|
135
|
+
# Get filter values to preserve them
|
|
136
|
+
filter_category = request.args.get('filter_category', '')
|
|
137
|
+
filter_version = request.args.get('filter_version', '')
|
|
138
|
+
|
|
139
|
+
# Get all form values to preserve them (convert MultiDict to regular dict, taking first value)
|
|
140
|
+
form_values = {k: v for k, v in request.args.items()}
|
|
91
141
|
|
|
92
|
-
# Handle selected pkt
|
|
93
|
-
if pkt:
|
|
94
|
-
pkt_string = ""
|
|
95
|
-
for k in pkt.__dict__.keys():
|
|
96
|
-
if not request.args.get(f"{type(pkt).__name__}_{k}"):
|
|
97
|
-
pkt_string += "{}={},".format(k, str(0))
|
|
98
|
-
else:
|
|
99
|
-
pkt_string += "{}={},".format(k, str(request.args.get(f"{type(pkt).__name__}_{k}")))
|
|
100
|
-
pkt = eval_pkt(f"{type(pkt).__name__}({pkt_string[0:-1]})")
|
|
101
|
-
output += pkt.dump()
|
|
102
142
|
print(output)
|
|
103
143
|
return render_template('generator.html',
|
|
104
144
|
app=app, title=title, output=txt2html(output),
|
|
105
|
-
pkt_types=wlt_pkt_types, pkt_types_list=
|
|
145
|
+
pkt_types=wlt_pkt_types, pkt_types_list=list(wlt_pkt_types.keys())[2:],
|
|
146
|
+
pkt_metadata=pkt_metadata, categories=categories, api_versions=api_versions,
|
|
147
|
+
wanted_pkt_type=wanted_pkt_type, form_values=form_values,
|
|
148
|
+
filter_category=filter_category, filter_version=filter_version)
|
|
106
149
|
|
|
107
150
|
def utils_tag2brg(app):
|
|
108
151
|
title = "Tag to Bridge Packet Converter"
|
|
@@ -295,26 +338,6 @@ def _read_json_safe(p: Path) -> Dict[str, Any]:
|
|
|
295
338
|
except Exception:
|
|
296
339
|
return {}
|
|
297
340
|
|
|
298
|
-
def _tooltip(meta: Dict[str, Any], fallback: str) -> str:
|
|
299
|
-
if not meta:
|
|
300
|
-
return fallback
|
|
301
|
-
# prefer human fields; keep it short
|
|
302
|
-
parts: List[str] = []
|
|
303
|
-
# for k in ("name", "title"):
|
|
304
|
-
# if isinstance(meta.get(k), str):
|
|
305
|
-
# parts.append(meta[k].strip())
|
|
306
|
-
for k in ("description", "desc", "objective", "purpose"):
|
|
307
|
-
if isinstance(meta.get(k), str):
|
|
308
|
-
parts.append(meta[k].strip())
|
|
309
|
-
break
|
|
310
|
-
if parts:
|
|
311
|
-
return "\n".join(parts[:2])
|
|
312
|
-
try:
|
|
313
|
-
s = json.dumps(meta, ensure_ascii=False, separators=(",", ":"))
|
|
314
|
-
return s[:240] + ("…" if len(s) > 240 else "")
|
|
315
|
-
except Exception:
|
|
316
|
-
return fallback
|
|
317
|
-
|
|
318
341
|
def scan_tests_dir(root: str | Path) -> Dict[str, Any]:
|
|
319
342
|
"""
|
|
320
343
|
Expect: <root>/<module>/<test>/{<test>.py, <test>.json}
|
|
@@ -359,13 +382,12 @@ def scan_tests_dir(root: str | Path) -> Dict[str, Any]:
|
|
|
359
382
|
"id": tid,
|
|
360
383
|
"module": mod_dir.name,
|
|
361
384
|
"name": test_dir.name,
|
|
362
|
-
# "label": test_dir.name.replace("_", " "),
|
|
363
385
|
"label": meta.get('name', test_dir.name.replace("_", " ")),
|
|
364
386
|
"dir": str(test_dir),
|
|
365
387
|
"py": str(py) if py else "",
|
|
366
388
|
"json_path": str(j) if j else "",
|
|
367
389
|
"meta": meta,
|
|
368
|
-
"tooltip":
|
|
390
|
+
"tooltip": meta.get('purpose', ""),
|
|
369
391
|
}
|
|
370
392
|
tests.append(item)
|
|
371
393
|
if py:
|