1import time
2
3import pytest
4from redfish_requests import Duration, RedfishHttpStatus
5
6
7def test_get_telemetry_service(redfish):
8    r = redfish.get(redfish.telemetry_service_path)
9    assert r["Status"]["State"] == "Enabled", "Invalid status of service"
10    assert (
11        Duration.to_seconds(r["MinCollectionInterval"]) > 0
12    ), "Invalid duration format"
13    assert r["MaxReports"] > 0, "Invalid count of max reports"
14
15
16def test_get_metric_definition_collection(redfish):
17    r = redfish.get(redfish.metric_definition_path)
18    assert "Members" in r, "Missing members property"
19    assert "Members@odata.count" in r, "Missing members count property"
20
21
22def test_verify_metric_definition_members_if_contains_metrics(redfish):
23    r = redfish.get(redfish.metric_definition_path)
24    for m in r["Members"]:
25        path = m["@odata.id"]
26        metricDefinition = redfish.get(path)
27        assert "MetricProperties" in metricDefinition, "Missing metrics"
28        assert len(metricDefinition["MetricProperties"]) > 0, "Missing metrics"
29
30
31def test_get_metric_definition_that_not_exist_expect_not_found(redfish):
32    redfish.get(
33        f"{redfish.metric_definition_path}/NotExisting",
34        code=RedfishHttpStatus.not_found,
35    )
36
37
38def test_get_metric_report_definition_collection(redfish):
39    r = redfish.get(redfish.metric_report_definition_path)
40    assert "Members" in r, "Missing members property"
41    assert "Members@odata.count" in r, "Missing members count property"
42
43
44def test_get_metric_report_definition_that_not_exist_expect_not_found(redfish):
45    redfish.get(
46        f"{redfish.metric_report_definition_path}/NotExisting",
47        code=RedfishHttpStatus.not_found,
48    )
49
50
51def test_get_metric_report_collection(redfish):
52    r = redfish.get(redfish.metric_report_path)
53    assert "Members" in r, "Missing members property"
54    assert "Members@odata.count" in r, "Missing members count property"
55
56
57def test_get_metric_report_that_not_exist_expect_not_found(redfish):
58    redfish.get(
59        f"{redfish.metric_report_path}/NotExisting",
60        code=RedfishHttpStatus.not_found,
61    )
62
63
64def test_post_report_definition_with_empty_body_expect_bad_request(redfish):
65    redfish.post(
66        redfish.metric_report_definition_path,
67        body={},
68        code=RedfishHttpStatus.bad_request,
69    )
70
71
72def test_post_report_definition_with_some_body_expect_bad_request(redfish):
73    redfish.post(
74        redfish.metric_report_definition_path,
75        body={"key": "value"},
76        code=RedfishHttpStatus.bad_request,
77    )
78
79
80def test_delete_non_exisiting_metric_report_definition(redfish):
81    redfish.delete(
82        f"{redfish.metric_report_definition_path}/NonExisitingReport",
83        code=RedfishHttpStatus.not_found,
84    )
85
86
87def test_add_report(redfish, report_definitions):
88    id = "Test"
89    report_definitions.add_report(id)
90    assert 1 == len(report_definitions.get_collection())
91    r = redfish.get(f"{redfish.metric_report_definition_path}/{id}")
92    assert r["Id"] == id, "Invalid Id, different then requested"
93    r = redfish.get(f"{redfish.metric_report_path}/{id}")
94    assert r["Id"] == id, "Invalid Id, different then requested"
95
96
97def test_add_report_above_max_report_expect_bad_request(
98    telemetry, report_definitions
99):
100    id = "Test"
101    for i in range(telemetry.max_reports):
102        report_definitions.add_report(id + str(i))
103    assert telemetry.max_reports == len(report_definitions.get_collection())
104    report_definitions.add_report(
105        id + str(telemetry.max_reports),
106        metrics=[],
107        interval=telemetry.min_interval,
108        code=RedfishHttpStatus.bad_request,
109    )
110
111
112def test_add_report_long_name(report_definitions):
113    report_definitions.add_report("Test" * 65)
114
115
116def test_add_report_twice_expect_bad_request(report_definitions):
117    report_definitions.add_report("Test")
118    report_definitions.add_report("Test", code=RedfishHttpStatus.bad_request)
119
120
121@pytest.mark.parametrize(
122    "actions",
123    [
124        [],
125        ["RedfishEvent"],
126        ["LogToMetricReportsCollection"],
127        ["RedfishEvent", "LogToMetricReportsCollection"],
128    ],
129)
130def test_add_report_with_actions(actions, redfish, report_definitions):
131    report_definitions.add_report("Test", actions=actions)
132    r = redfish.get(f"{redfish.metric_report_definition_path}/Test")
133    assert (
134        r["ReportActions"] == actions
135    ), "Invalid actions, different then requested"
136
137
138@pytest.mark.parametrize(
139    "invalid_actions",
140    [
141        ["NonExisting"],
142        ["RedfishEvent", "Partially"],
143        ["LogToMetricNotThisOne"],
144    ],
145)
146def test_add_report_with_invalid_actions_expect_bad_request(
147    invalid_actions, report_definitions
148):
149    report_definitions.add_report(
150        "Test", actions=invalid_actions, code=RedfishHttpStatus.bad_request
151    )
152
153
154@pytest.mark.parametrize("invalid_id", ["test_-", "t t", "T.T", "T,t", "T:t"])
155def test_add_report_with_invalid_id_expect_bad_request(
156    invalid_id, report_definitions
157):
158    report_definitions.add_report(
159        invalid_id, code=RedfishHttpStatus.bad_request
160    )
161
162
163def test_add_report_with_metric(redfish, telemetry, report_definitions):
164    if len(telemetry.metrics) <= 0:
165        pytest.skip("Redfish has no sensor available")
166    metric = {"MetricId": "Id1", "MetricProperties": [telemetry.metrics[0]]}
167    report_definitions.add_report("Test", metrics=[metric])
168    r = redfish.get(redfish.metric_report_definition_path + "/Test")
169    assert len(r["Metrics"]) == 1, "Invalid Metrics, different then requested"
170    assert (
171        r["Metrics"][0]["MetricId"] == metric["MetricId"]
172    ), "Invalid MetricId, different then requested"
173    assert (
174        r["Metrics"][0]["MetricProperties"] == metric["MetricProperties"]
175    ), "Invalid MetricProperties, different then requested"
176
177
178def test_add_report_with_invalid_metric_expect_bad_request(report_definitions):
179    metric = {
180        "MetricId": "Id1",
181        "MetricProperties": [
182            "/redfish/v1/Chassis/chassis/Sensors/NonExisting/Reading"
183        ],
184    }
185    report_definitions.add_report(
186        "Test", metrics=[metric], code=RedfishHttpStatus.bad_request
187    )
188
189
190def test_add_report_with_many_metrics(redfish, telemetry, report_definitions):
191    if len(telemetry.metrics) <= 0:
192        pytest.skip("Redfish has no sensor available")
193    metrics = []
194    for i, prop in enumerate(telemetry.metrics):
195        metrics.append({"MetricId": f"Id{str(i)}", "MetricProperties": [prop]})
196    report_definitions.add_report("Test", metrics=metrics)
197    r = redfish.get(redfish.metric_report_definition_path + "/Test")
198    assert len(r["Metrics"]) == len(
199        telemetry.metrics
200    ), "Invalid Metrics, different then requested"
201
202
203def test_add_report_on_request_with_metric_expect_updated_metric_report(
204    redfish, telemetry, report_definitions
205):
206    if len(telemetry.metrics) <= 0:
207        pytest.skip("Redfish has no sensor available")
208    metric = {"MetricId": "Id1", "MetricProperties": [telemetry.metrics[0]]}
209    report_definitions.add_report("Test", metrics=[metric], type="OnRequest")
210    r = redfish.get(redfish.metric_report_path + "/Test")
211    assert len(r["MetricValues"]) > 0, "Missing MetricValues"
212    metric_value = r["MetricValues"][0]
213    assert metric_value["MetricValue"], "Missing MetricValues"
214    assert (
215        metric_value["MetricId"] == metric["MetricId"]
216    ), "Different Id then set in request"
217    assert (
218        metric_value["MetricProperty"] == metric["MetricProperties"][0]
219    ), "Different MetricProperty then set in request"
220
221
222def test_add_report_periodic_with_metric_expect_updated_metric_report(
223    redfish, telemetry, report_definitions
224):
225    if len(telemetry.metrics) <= 0:
226        pytest.skip("Redfish has no sensor available")
227    metric = {"MetricId": "Id1", "MetricProperties": [telemetry.metrics[0]]}
228    report_definitions.add_report(
229        "Test",
230        metrics=[metric],
231        type="Periodic",
232        interval=Duration.to_iso8061(telemetry.min_interval),
233    )
234    time.sleep(telemetry.min_interval + 1)
235    r = redfish.get(redfish.metric_report_path + "/Test")
236    assert len(r["MetricValues"]) > 0, "Missing MetricValues"
237    metric_value = r["MetricValues"][0]
238    assert metric_value["MetricValue"], "Missing MetricValues"
239    assert (
240        metric_value["MetricId"] == metric["MetricId"]
241    ), "Different Id then set in request"
242    assert (
243        metric_value["MetricProperty"] == metric["MetricProperties"][0]
244    ), "Different MetricProperty then set in request"
245
246
247@pytest.mark.parametrize("interval", [10, 60, 2400, 90000])
248def test_add_report_check_if_duration_is_set(
249    interval, redfish, telemetry, report_definitions
250):
251    if interval < telemetry.min_interval:
252        pytest.skip("Interval is below minimal acceptable value, skipping")
253    id = f"Test{str(interval)}"
254    report_definitions.add_report(
255        id, type="Periodic", interval=Duration.to_iso8061(interval)
256    )
257    r = redfish.get(f"{redfish.metric_report_definition_path}/{id}")
258    assert r["Schedule"]["RecurrenceInterval"], "Missing RecurrenceInterval"
259    r_interval = Duration.to_seconds(r["Schedule"]["RecurrenceInterval"])
260    assert interval == r_interval, "Invalid interval, different then requested"
261
262
263@pytest.mark.parametrize(
264    "invalid", ["50000", "P12ST", "PT12S12", "PPPPD222T222H222M222.222S"]
265)
266def test_add_report_with_invalid_duration_response_bad_request(
267    invalid, report_definitions
268):
269    r = report_definitions.add_report(
270        "Test",
271        type="Periodic",
272        interval=invalid,
273        code=RedfishHttpStatus.bad_request,
274    )
275    assert r["error"]["@Message.ExtendedInfo"][
276        0
277    ], "Wrong response, not an error"
278    info = r["error"]["@Message.ExtendedInfo"][0]
279    assert (
280        "RecurrenceInterval" in info["MessageArgs"]
281    ), 'Wrong response, should contain "RecurrenceInterval"'
282
283
284def test_stress_add_reports_with_many_metrics_check_metric_reports(
285    redfish, telemetry, report_definitions
286):
287    if len(telemetry.metrics) <= 0:
288        pytest.skip("Redfish has no sensor available")
289    metrics = []
290    for i, prop in enumerate(telemetry.metrics):
291        metrics.append({"MetricId": f"Id{str(i)}", "MetricProperties": [prop]})
292    for i in range(telemetry.max_reports):
293        report_definitions.add_report(f"Test{str(i)}", metrics=metrics)
294    for i in range(telemetry.max_reports):
295        r = redfish.get(
296            f"{redfish.metric_report_definition_path}/Test{str(i)}"
297        )
298        assert len(r["Metrics"]) == len(
299            telemetry.metrics
300        ), "Invalid Metrics, different then requested"
301    for i in range(telemetry.max_reports):
302        r = redfish.get(f"{redfish.metric_report_path}/Test{str(i)}")
303        assert len(r["MetricValues"]) > 0, "Missing MetricValues"
304