diff --git a/CHANGELOG.md b/CHANGELOG.md index 58cad6a..c6a0ba7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +**21/09/2023** [Version 3.6.2] + - Add a prefix (`/elcm/api/v1/`) to all endpoints + - Allow defining and return a more complete description of the KPIs in the `/elcm/api/v1//kpis` endpoint + **09/11/2022** [Version 3.6.1] - Allow defining a set of KPIs per TestCase - Implement `/execution//kpis` endpoint diff --git a/Facility/Loader/testcase_loader.py b/Facility/Loader/testcase_loader.py index b65e16c..20d723d 100644 --- a/Facility/Loader/testcase_loader.py +++ b/Facility/Loader/testcase_loader.py @@ -25,7 +25,7 @@ class TestCaseLoader(Loader): testCases: Dict[str, List[ActionInformation]] = {} extra: Dict[str, Dict[str, object]] = {} dashboards: Dict[str, List[DashboardPanel]] = {} - kpis: Dict[str, List[Tuple[str, str]]] = {} + kpis: Dict[str, List[Tuple[str, str, str, str]]] = {} # (Measurement, KPI, Type, Description) parameters: Dict[str, Tuple[str, str]] = {} # For use only while processing data, not necessary afterwards @classmethod @@ -100,10 +100,22 @@ def validateKPIs(cls, key: str, defs: TestCaseData) -> [(Level, str)]: (Level.ERROR, f"KPIs for '{measurement}' ({key}) are not a list. Found '{kpiList}'")) elif len(kpiList) == 0: validation.append( - (Level.ERROR, f"'{measurement}' ({key}) defines an empty listf of KPIs")) + (Level.ERROR, f"'{measurement}' ({key}) defines an empty list of KPIs")) else: - for kpi in sorted(kpiList): - kpis.append((measurement, kpi)) + for kpi in sorted(kpiList, key=lambda x: x if isinstance(x, str) else x.get('Name', '')): + description = kind = "" + if isinstance(kpi, str): + name = kpi + elif isinstance(kpi, dict): + name = kpi.get('Name', '') + description = kpi.get('Description', '') + kind = kpi.get('Type', '') + else: + validation.append( + (Level.ERROR, f"KPI definitions for '{measurement}' must either be str or a " + f"dictionary (keys ['Name', 'Type', 'Description']). Found '{kpi}'")) + continue + kpis.append((measurement, name, kind, description)) except Exception as e: validation.append((Level.ERROR, f"Could not read KPIs dictionary for testcase '{key}': {e}")) diff --git a/Facility/facility.py b/Facility/facility.py index 72df8a4..07d5d23 100644 --- a/Facility/facility.py +++ b/Facility/facility.py @@ -24,7 +24,7 @@ class Facility: testCases: Dict[str, List[ActionInformation]] = {} extra: Dict[str, Dict[str, object]] = {} dashboards: Dict[str, List[DashboardPanel]] = {} - kpis: Dict[str, List[Tuple[str, str]]] = {} + kpis: Dict[str, List[Tuple[str, str, str, str]]] = {} resources: Dict[str, Resource] = {} scenarios: Dict[str, Dict] = {} @@ -98,7 +98,7 @@ def GetTestCaseExtra(cls, id: str) -> Dict[str, object]: return cls.extra.get(id, {}) @classmethod - def GetTestCaseKPIs(cls, id: str) -> List[Tuple[str, str]]: + def GetTestCaseKPIs(cls, id: str) -> List[Tuple[str, str, str, str]]: return cls.kpis.get(id, []) @classmethod diff --git a/Scheduler/execution/routes.py b/Scheduler/execution/routes.py index 82b4f27..e09ad39 100644 --- a/Scheduler/execution/routes.py +++ b/Scheduler/execution/routes.py @@ -138,7 +138,14 @@ def kpis(executionId: int): for testcase in descriptor.TestCases: kpis.update(Facility.GetTestCaseKPIs(testcase)) - return jsonify({"KPIs": sorted(kpis)}) + res = [] + for kpi in sorted(kpis): + measurement, name, kind, description = kpi + res.append({ + 'Measurement': measurement, 'KPI': name, 'Type': kind, 'Description': description + }) + + return jsonify({"KPIs": res}) else: return f"Execution {executionId} not found", 404 diff --git a/docs/A1_ENDPOINTS.md b/docs/A1_ENDPOINTS.md index f1abfe5..bcd6582 100644 --- a/docs/A1_ENDPOINTS.md +++ b/docs/A1_ENDPOINTS.md @@ -48,8 +48,17 @@ Returns a copy of the Experiment Descriptor that was used to define the executio ### [GET] `/elcm/api/v1/execution//kpis` -Returns a dictionary with a single `KPIs` key, containing a list of pairs (`measurement`, `kpi`) that are considered of -interest. +Returns a dictionary with a single `KPIs` key, containing a list of objects that describe KPIs that are considered of +interest. The objects have the following format: + +```text +{ + "Measurement": , + "KPI": , + "Type": , + "Description": +} +``` > These values can be used as part of queries to the [Analytics Module](https://github.com/5genesis/Analytics), in order > to extract a sub-set of important KPIs from all the generated measurements.