diff options
Diffstat (limited to 'resources/libraries/python/model')
-rw-r--r-- | resources/libraries/python/model/ExportJson.py | 28 | ||||
-rw-r--r-- | resources/libraries/python/model/ExportResult.py | 13 | ||||
-rw-r--r-- | resources/libraries/python/model/validate.py | 7 |
3 files changed, 30 insertions, 18 deletions
diff --git a/resources/libraries/python/model/ExportJson.py b/resources/libraries/python/model/ExportJson.py index 3f923d6d0e..a83bf5ec88 100644 --- a/resources/libraries/python/model/ExportJson.py +++ b/resources/libraries/python/model/ExportJson.py @@ -1,4 +1,4 @@ -# Copyright (c) 2024 Cisco and/or its affiliates. +# Copyright (c) 2025 Cisco and/or its affiliates. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at: @@ -86,7 +86,7 @@ class ExportJson(): return test_type def export_pending_data(self): - """Write the accumulated data to disk. + """Write the data to disk, raise error if invalid. Create missing directories. Reset both file path and data to avoid writing multiple times. @@ -97,23 +97,27 @@ class ExportJson(): If no file path is set, do not write anything, as that is the failsafe behavior when caller from unexpected place. - Aso do not write anything when EXPORT_JSON constant is false. + Also do not write anything when EXPORT_JSON constant is false. - Regardless of whether data was written, it is cleared. + :raises: ValidationError if data export does not conform to schema. """ + error = None if not Constants.EXPORT_JSON or not self.file_path: self.data = None self.file_path = None return new_file_path = write_output(self.file_path, self.data) - # Data is going to be cleared (as a sign that export succeeded), - # so this is the last chance to detect if it was for a test case. - is_testcase = "result" in self.data + if "result" in self.data: + error = validate(new_file_path, self.validators["tc_info"]) + if error: + # Mark as failed and re-export. + self.data["passed"] = False + self.data["message"] = str(error) + write_output(self.file_path, self.data) self.data = None - # Validation for output goes here when ready. self.file_path = None - if is_testcase: - validate(new_file_path, self.validators["tc_info"]) + if error: + raise error def warn_on_bad_export(self): """If bad state is detected, log a warning and clean up state.""" @@ -363,6 +367,10 @@ class ExportJson(): result_type = result_node["type"] if result_type == "unknown": # Device or something else not supported. + # Also could be MRR with all trials negative, write as a failure. + self.data["passed"] = False + self.data["message"] = "No result exported." + # TODO: Raise real Robot error after writing this JSON. return # Compute avg and stdev for mrr (rate and bandwidth). diff --git a/resources/libraries/python/model/ExportResult.py b/resources/libraries/python/model/ExportResult.py index f155848913..b751e593f9 100644 --- a/resources/libraries/python/model/ExportResult.py +++ b/resources/libraries/python/model/ExportResult.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Cisco and/or its affiliates. +# Copyright (c) 2025 Cisco and/or its affiliates. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at: @@ -100,7 +100,7 @@ def append_mrr_value(mrr_value, mrr_unit, bandwidth_value=None, bandwidth_unit="bps"): """Store mrr value to proper place so it is dumped into json. - The value is appended only when unit is not empty. + Raises an error if the arguments would lead to invalid json. :param mrr_value: Forwarding rate from MRR trial. :param mrr_unit: Unit of measurement for the rate. @@ -109,19 +109,22 @@ def append_mrr_value(mrr_value, mrr_unit, bandwidth_value=None, :type mrr_unit: str :type bandwidth_value: Optional[float] :type bandwidth_unit: Optional[str] + :raises RuntimeError: If mrr_unit is missing or any value is negative. """ if not mrr_unit: - return + raise RuntimeError(f"Cannot be falsey: {mrr_unit=}") data = get_export_data() data["result"]["type"] = "mrr" - for node_val, node_unit, node_name in ((mrr_value, mrr_unit, "rate"), (bandwidth_value, bandwidth_unit, "bandwidth")): if node_val is not None: + node_val = float(node_val) + if node_val < 0: + raise RuntimeError(f"Cannot be negative: {node_val=}") node = descend(descend(data["result"], "receive_rate"), node_name) node["unit"] = str(node_unit) values_list = descend(node, "values", list) - values_list.append(float(node_val)) + values_list.append(node_val) def export_search_bound(text, value, unit, bandwidth=None): diff --git a/resources/libraries/python/model/validate.py b/resources/libraries/python/model/validate.py index 85c4b993c9..d3e1bdf706 100644 --- a/resources/libraries/python/model/validate.py +++ b/resources/libraries/python/model/validate.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Cisco and/or its affiliates. +# Copyright (c) 2025 Cisco and/or its affiliates. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at: @@ -52,11 +52,12 @@ def validate(file_path, validator): :param validator: Validator instance to use for validation. :type file_path: str :type validator: jsonschema.validators.Validator - :raises ValidationError: If schema validation fails. + :returns: None if valid, error if invalid. + :rtype: Optional[ValidationError] """ with open(file_path, "rt", encoding="utf-8") as file_in: instance = json.load(file_in) error = jsonschema.exceptions.best_match(validator.iter_errors(instance)) if error is not None: print(json.dumps(instance, indent=4)) - raise error + return error |