Add simple Redfish tests

Added Redfish tests to validate connection between Redfish
Telemetry that is implemented in bmcweb and Telemetry service.

Change-Id: Iacc63aeb7f2852d5acac5d5615f98b402f7c4417
Signed-off-by: Wludzik, Jozef <jozef.wludzik@intel.com>
diff --git a/redfish-tests/redfish_requests.py b/redfish-tests/redfish_requests.py
new file mode 100644
index 0000000..28dee84
--- /dev/null
+++ b/redfish-tests/redfish_requests.py
@@ -0,0 +1,127 @@
+import enum
+import math
+import re
+import requests
+
+
+class RedfishHttpStatus(enum.IntEnum):
+    ok = 200
+    created = 201
+    no_content = 204
+    bad_request = 400
+    not_found = 404
+    internal_server_error = 500
+
+
+class RedfishRequest:
+    telemetry_service_path = '/redfish/v1/TelemetryService'
+    metric_definition_path = f'{telemetry_service_path}/MetricDefinitions'
+    metric_report_definition_path = \
+        f'{telemetry_service_path}/MetricReportDefinitions'
+    metric_report_path = f'{telemetry_service_path}/MetricReports'
+
+    def __init__(self, host_addr, username, password):
+        self.host_addr = host_addr
+        self.username = username
+        self.password = password
+
+    def get(self, path, code=RedfishHttpStatus.ok):
+        u = self.host_addr + path
+        r = requests.get(u, auth=(self.username, self.password), verify=False)
+        assert r.status_code == code, \
+            f'{r.status_code} == {code} on path {u}\n{r.text}'
+        print(r.text)
+        return r.json()
+
+    def post(self, path, body, code=RedfishHttpStatus.created):
+        u = self.host_addr + path
+        r = requests.post(u, auth=(self.username, self.password), verify=False,
+                          json=body)
+        assert r.status_code == code, \
+            f'{r.status_code} == {code} on path {u}\n{r.text}'
+        print(r.text)
+        return r.json()
+
+    def delete(self, path, code=RedfishHttpStatus.no_content):
+        u = self.host_addr + path
+        r = requests.delete(u, auth=(self.username, self.password),
+                            verify=False)
+        assert r.status_code == code, \
+            f'{r.status_code} == {code} on path {u}\n{r.text}'
+
+
+class TelemetryService:
+    def __init__(self, redfish, metric_limit):
+        r = redfish.get(redfish.telemetry_service_path)
+        self.min_interval = Duration.to_seconds(r['MinCollectionInterval'])
+        self.max_reports = r['MaxReports']
+        self.metrics = []
+        r = redfish.get(redfish.metric_definition_path)
+        for m in r['Members']:
+            path = m['@odata.id']
+            metricDef = redfish.get(path)
+            self.metrics += [x for x in metricDef['MetricProperties']]
+        self.metrics = self.metrics[:metric_limit]
+
+
+class ReportDef:
+    def __init__(self, redfish):
+        self.redfish = redfish
+
+    def get_collection(self):
+        r = self.redfish.get(self.redfish.metric_report_definition_path)
+        return [x['@odata.id'] for x in r['Members']]
+
+    def add_report(self, id, metrics=None, type='OnRequest', actions=None,
+                   interval=None, code=RedfishHttpStatus.created):
+        body = {
+            'Id': id,
+            'Metrics': [],
+            'MetricReportDefinitionType': type,
+            'ReportActions': ['RedfishEvent', 'LogToMetricReportsCollection']
+        }
+        if metrics is not None:
+            body['Metrics'] = metrics
+        if actions is not None:
+            body['ReportActions'] = actions
+        if interval is not None:
+            body['Schedule'] = {'RecurrenceInterval': interval}
+        return self.redfish.post(self.redfish.metric_report_definition_path,
+                                 body, code)
+
+    def delete_report(self, path):
+        self.redfish.delete(f'{path}')
+
+
+class Duration:
+    def __init__(self):
+        pass
+
+    def to_iso8061(time):
+        assert time >= 0, 'Invalid argument, time is negative'
+        days = int(time / (24 * 60 * 60))
+        time = math.fmod(time, (24 * 60 * 60))
+        hours = int(time / (60 * 60))
+        time = math.fmod(time, (60 * 60))
+        minutes = int(time / 60)
+        time = round(math.fmod(time, 60), 3)
+        return f'P{str(days)}DT{str(hours)}H{str(minutes)}M{str(time)}S'
+
+    def to_seconds(duration):
+        r = re.fullmatch(r'-?P(\d+D)?(T(\d+H)?(\d+M)?(\d+(.\d+)?S)?)?',
+                         duration)
+        assert r, 'Invalid argument, not match with regex'
+        days = r.group(1)
+        hours = r.group(3)
+        minutes = r.group(4)
+        seconds = r.group(5)
+        result = 0
+        if days is not None:
+            result += int(days[:-1]) * 60 * 60 * 24
+        if hours is not None:
+            result += int(hours[:-1]) * 60 * 60
+        if minutes is not None:
+            result += int(minutes[:-1]) * 60
+        if seconds is not None:
+            result += float(seconds[:-1])
+        return result