aboutsummaryrefslogtreecommitdiffstats
path: root/resources/libraries/python/model
diff options
context:
space:
mode:
Diffstat (limited to 'resources/libraries/python/model')
-rw-r--r--resources/libraries/python/model/ExportJson.py28
-rw-r--r--resources/libraries/python/model/ExportResult.py13
-rw-r--r--resources/libraries/python/model/validate.py7
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