From 5f4eaaaa20148487a3ef0a32580c927ab9b103c7 Mon Sep 17 00:00:00 2001 From: mahmamdouh Date: Mon, 22 Dec 2025 15:04:06 +0100 Subject: [PATCH] add branch validation to queue --- .../testarena_1/app/routes/jobs.py | 70 ++++-- .../testarena_1/app/static/css/style.css | 130 +++++++++++ .../app/templates/jobs/submit.html | 30 ++- .../app/templates/jobs/submit_step2.html | 204 ++++++++++++++++-- 4 files changed, 394 insertions(+), 40 deletions(-) diff --git a/asf-cloud-server/testarena_1/app/routes/jobs.py b/asf-cloud-server/testarena_1/app/routes/jobs.py index fc07b27..706b64c 100644 --- a/asf-cloud-server/testarena_1/app/routes/jobs.py +++ b/asf-cloud-server/testarena_1/app/routes/jobs.py @@ -138,26 +138,61 @@ def submit_step1(): } }) - # If successful, get available scenarios (mock for now) - scenarios = [ - 'Scenario_1_Basic_Test', - 'Scenario_2_Advanced_Test', - 'Scenario_3_Integration_Test', - 'Scenario_4_Performance_Test', - 'Scenario_5_Security_Test' - ] + # If successful, run scenario scan to get available scenarios + print(f"[DEBUG] Running scenario scan...") + scan_cmd = f"sshpass -p '{ssh_password}' ssh {ssh_options} {ssh_user}@{ssh_host} 'python3 TPF/Sensor_hub_repo/Tools/TPF/scenario_scan.py'" + print(f"[DEBUG] Executing scan command: {scan_cmd.replace(ssh_password, '***')}") + + scan_result = subprocess.run(scan_cmd, shell=True, capture_output=True, text=True, timeout=120) + + print(f"[DEBUG] Scan result - Return code: {scan_result.returncode}") + print(f"[DEBUG] Scan stdout: {scan_result.stdout}") + print(f"[DEBUG] Scan stderr: {scan_result.stderr}") + + # Parse the JSON response from scenario scan + try: + scan_data = json.loads(scan_result.stdout) + organized_data = scan_data.get('organized_data', {}) + scenario_map = scan_data.get('scenario_map', {}) + + print(f"[DEBUG] Found {len(scenario_map)} scenarios in {len(organized_data)} categories") + + except json.JSONDecodeError as e: + print(f"[ERROR] Failed to parse scenario scan JSON: {e}") + print(f"[ERROR] Raw output: {scan_result.stdout}") + # Fallback to mock data if scan fails + organized_data = { + "drivers": { + "diag_protocol_stack": ["diag_protocol_stack_init_test"] + }, + "application_layer": { + "data_pool": ["data_pool_init_test"], + "actuator_manager": ["actuator_manager_init_test2", "actuator_manager_init_test"], + "event_system": ["event_system_init_test"] + } + } + scenario_map = { + "diag_protocol_stack_init_test": "drivers/diag_protocol_stack/test/diag_protocol_stack_init_test.test_scenario.xml", + "data_pool_init_test": "application_layer/DP_stack/data_pool/test/data_pool_init_test.test_scenario.xml", + "actuator_manager_init_test2": "application_layer/business_stack/actuator_manager/test/actuator_manager_init_test2.test_scenario.xml", + "actuator_manager_init_test": "application_layer/business_stack/actuator_manager/test/actuator_manager_init_test.test_scenario.xml", + "event_system_init_test": "application_layer/business_stack/event_system/test/event_system_init_test.test_scenario.xml" + } print(f"[DEBUG] Branch validation successful for: {branch_name}") return jsonify({ 'success': True, - 'scenarios': scenarios, + 'organized_data': organized_data, + 'scenario_map': scenario_map, 'message': f'Branch "{branch_name}" validated successfully', 'output': full_output, 'debug': { 'clone_returncode': clone_result.returncode, 'checkout_returncode': checkout_result.returncode, - 'branch_name': branch_name + 'scan_returncode': scan_result.returncode if 'scan_result' in locals() else 'N/A', + 'branch_name': branch_name, + 'scenarios_found': len(scenario_map) } }) @@ -182,15 +217,20 @@ def submit_step1(): @login_required def submit_step2_validated(): branch_name = request.form.get('branch_name') - scenarios_json = request.form.get('scenarios') + organized_data_json = request.form.get('organized_data') + scenario_map_json = request.form.get('scenario_map') try: - scenarios = json.loads(scenarios_json) - except: - flash('Invalid scenarios data', 'error') + organized_data = json.loads(organized_data_json) if organized_data_json else {} + scenario_map = json.loads(scenario_map_json) if scenario_map_json else {} + except json.JSONDecodeError: + flash('Invalid scenario data', 'error') return redirect(url_for('jobs.submit')) - return render_template('jobs/submit_step2.html', branch_name=branch_name, scenarios=scenarios) + return render_template('jobs/submit_step2.html', + branch_name=branch_name, + organized_data=organized_data, + scenario_map=scenario_map) @login_required def submit_step2(): branch_name = request.form.get('branch_name') diff --git a/asf-cloud-server/testarena_1/app/static/css/style.css b/asf-cloud-server/testarena_1/app/static/css/style.css index 34a74e4..f8c5ed6 100644 --- a/asf-cloud-server/testarena_1/app/static/css/style.css +++ b/asf-cloud-server/testarena_1/app/static/css/style.css @@ -623,4 +623,134 @@ body { background: #9ca3af; cursor: not-allowed; opacity: 0.6; +}/ +* Scenario Tree Styles */ +.scenario-controls { + margin: 20px 0; + padding: 15px; + background: var(--light); + border-radius: 8px; + display: flex; + align-items: center; + gap: 10px; +} + +.scenario-tree { + border: 1px solid var(--border); + border-radius: 8px; + padding: 20px; + background: white; + margin: 20px 0; + max-height: 500px; + overflow-y: auto; +} + +.tree-layer { + margin-bottom: 15px; +} + +.tree-stack { + margin-left: 20px; + margin-bottom: 10px; +} + +.tree-scenario { + margin-left: 40px; + margin-bottom: 5px; +} + +.tree-node { + display: flex; + align-items: center; + gap: 8px; + padding: 8px 0; + cursor: pointer; + user-select: none; +} + +.tree-toggle { + width: 16px; + height: 16px; + display: inline-flex; + align-items: center; + justify-content: center; + font-size: 12px; + color: var(--primary); + font-weight: bold; + cursor: pointer; +} + +.tree-spacer { + width: 16px; + height: 16px; +} + +.tree-label { + font-weight: 500; + cursor: pointer; + margin: 0; +} + +.layer-label { + font-size: 16px; + font-weight: 600; + color: var(--dark); +} + +.stack-label { + font-size: 14px; + font-weight: 500; + color: #4b5563; +} + +.scenario-label { + font-size: 13px; + font-weight: 400; + color: #6b7280; +} + +.tree-children { + margin-top: 5px; +} + +.layer-checkbox, .stack-checkbox, .scenario-checkbox { + width: 16px; + height: 16px; + cursor: pointer; +} + +.layer-node:hover { + background: rgba(59, 130, 246, 0.05); + border-radius: 4px; +} + +.stack-node:hover { + background: rgba(16, 185, 129, 0.05); + border-radius: 4px; +} + +.scenario-node:hover { + background: rgba(245, 158, 11, 0.05); + border-radius: 4px; +} + +/* Indeterminate checkbox styling */ +input[type="checkbox"]:indeterminate { + background-color: var(--primary); + border-color: var(--primary); +} + +input[type="checkbox"]:indeterminate::before { + content: '−'; + color: white; + font-weight: bold; + display: block; + text-align: center; + line-height: 14px; +} + +/* Selection count styling */ +#selectionCount { + color: var(--primary); + font-size: 14px; } \ No newline at end of file diff --git a/asf-cloud-server/testarena_1/app/templates/jobs/submit.html b/asf-cloud-server/testarena_1/app/templates/jobs/submit.html index d546932..a9924e6 100644 --- a/asf-cloud-server/testarena_1/app/templates/jobs/submit.html +++ b/asf-cloud-server/testarena_1/app/templates/jobs/submit.html @@ -54,7 +54,8 @@ {% endblock %} diff --git a/asf-cloud-server/testarena_1/app/templates/jobs/submit_step2.html b/asf-cloud-server/testarena_1/app/templates/jobs/submit_step2.html index 8d581b3..7fdfa32 100644 --- a/asf-cloud-server/testarena_1/app/templates/jobs/submit_step2.html +++ b/asf-cloud-server/testarena_1/app/templates/jobs/submit_step2.html @@ -33,36 +33,210 @@ Branch: {{ branch_name }} -
+ + + -
- +
+ + + 0 scenarios selected
-
- {% for scenario in scenarios %} -
- - +
+ {% for layer_name, layer_data in organized_data.items() %} +
+
+ + + +
+ +
{% endfor %}
Back - +
{% endblock %}