11"""
22ArduPilot log quality checker.
33
4- Validates that the messages required by each analysis plugin, and configuration are present,
5- and that logged record matches its FMT schema.
4+ Validates that the messages and params required by the Methodic Configurator configuration
5+ steps are present, also checks if a specific analysis can be performed and that logged records match their FMT schema.
66
77SPDX-FileCopyrightText: 2024-2026 Amilcar do Carmo Lucas <amilcar.lucas@iav.de>
88
1616from os import path as os_path
1717from typing import Any
1818
19- from ardupilot_methodic_configurator . log_analysis . backend_log_extraction import LogData , MessageSchema
19+ from backend_log_extraction import LogData , MessageSchema
2020
2121
22- def load_analysis_plugins () -> dict [str , Any ]:
23- """Load the analysis plugin from JSON ."""
24- plugin_file = os_path .join (
25- os_path .dirname (os_path .abspath (__file__ )),
26- "analysis_plugins .json" ,
22+ def load_configuration_steps () -> dict [str , Any ]:
23+ """Load the Methodic Configurator configuration steps ."""
24+ config_file = os_path .join (
25+ os_path .dirname (os_path .dirname ( os_path . abspath (__file__ ) )),
26+ "configuration_steps_ArduCopter .json" ,
2727 )
28+
2829 try :
29- with open (plugin_file , encoding = "utf-8" ) as file :
30+ with open (config_file , encoding = "utf-8" ) as file :
3031 return json_load (file )
3132 except FileNotFoundError :
32- logging_error ("Analysis plugins '%s' not found" , plugin_file )
33+ logging_error ("Configuration file '%s' not found" , config_file )
3334 except JSONDecodeError as e :
34- logging_error ("Error in analysis plugins '%s': %s" , plugin_file , e )
35+ logging_error ("Error in configuration file '%s': %s" , config_file , e )
36+
3537 return {}
3638
3739
38- ANALYSIS_PLUGINS = load_analysis_plugins ()
40+ CONFIGURATION_STEPS = load_configuration_steps ()
3941
4042
4143@dataclass
@@ -47,17 +49,17 @@ class MessageValidation:
4749
4850
4951@dataclass
50- class PluginValidationResult :
51- """Validation result for one analysis plugin (analysis_plugins.json) ."""
52+ class StepValidationResult :
53+ """Validation result for configuration step ."""
5254
53- plugin : str
55+ step : str
5456 name : str
5557 valid : bool
5658 message_results : dict [str , MessageValidation ]
5759
5860
5961class LogQualityChecker :
60- """Checks whether a log is suitable for each analysis plugin ."""
62+ """Checks whether a log contains the required messages for each configuration step ."""
6163
6264 def validate_fmt_schema (self , schema : MessageSchema , records : list [dict ]) -> MessageValidation :
6365 """
@@ -71,7 +73,6 @@ def validate_fmt_schema(self, schema: MessageSchema, records: list[dict]) -> Mes
7173 MessageValidation
7274
7375 """
74- # Store the issues iteratively
7576 issues : list [str ] = []
7677
7778 if not schema .fields :
@@ -87,7 +88,6 @@ def validate_fmt_schema(self, schema: MessageSchema, records: list[dict]) -> Mes
8788
8889 if not records :
8990 issues .append (f"{ schema .name } has no logging data" )
90-
9191 else :
9292 record = records [0 ]
9393 actual_fields = [field for field in record .keys () if field != "mavpackettype" ] # noqa: SIM118
@@ -100,32 +100,42 @@ def validate_fmt_schema(self, schema: MessageSchema, records: list[dict]) -> Mes
100100 issues = issues ,
101101 )
102102
103- def validate_fmt_plugins (self , log_data : LogData ) -> list [PluginValidationResult ]:
103+ def validate_configuration_steps (self , log_data : LogData ) -> list [StepValidationResult ]:
104104 """
105- Validate every analysis plugin .
105+ Validate the messages required by each configuration step .
106106
107107 Args:
108108 log_data: Parsed log.
109109
110110 Returns:
111- List of plugin validation results.
111+ List of validation results.
112112
113113 """
114- results : list [PluginValidationResult ] = []
114+ results : list [StepValidationResult ] = []
115+
116+ for step_name , step in CONFIGURATION_STEPS ["steps" ].items ():
117+ related_messages = step .get ("related_bin_messages" )
118+ if not related_messages :
119+ continue
115120
116- for plugin_name , plugin in ANALYSIS_PLUGINS .items ():
117- plugin_valid = True
121+ step_valid = True
118122 message_results : dict [str , MessageValidation ] = {}
119123
120- for message_name in plugin ["required_messages" ]:
124+ for message_name , message_info in related_messages .items ():
125+ required = message_info .get ("required" , False )
126+
121127 schema = log_data .schemas .get (message_name )
122128
123129 if schema is None :
124- plugin_valid = False
125- message_results [message_name ] = MessageValidation (
130+ validation = MessageValidation (
126131 valid = False ,
127132 issues = ["Schema not found" ],
128133 )
134+
135+ if required :
136+ step_valid = False
137+
138+ message_results [message_name ] = validation
129139 continue
130140
131141 records = log_data .raw_messages .get (message_name , [])
@@ -135,16 +145,16 @@ def validate_fmt_plugins(self, log_data: LogData) -> list[PluginValidationResult
135145 records = records ,
136146 )
137147
138- if not validation .valid :
139- plugin_valid = False
148+ if required and not validation .valid :
149+ step_valid = False
140150
141151 message_results [message_name ] = validation
142152
143153 results .append (
144- PluginValidationResult (
145- plugin = plugin_name ,
146- name = plugin [ "name" ] ,
147- valid = plugin_valid ,
154+ StepValidationResult (
155+ step = step_name ,
156+ name = step . get ( "blog_text" , step_name ) ,
157+ valid = step_valid ,
148158 message_results = message_results ,
149159 )
150160 )
0 commit comments