1 #include "common/test/mocked_utils.hpp"
2 #include "common/types.hpp"
3 #include "common/utils.hpp"
4 #include "host-bmc/dbus_to_event_handler.hpp"
5 #include "libpldmresponder/event_parser.hpp"
6 #include "libpldmresponder/pdr.hpp"
7 #include "libpldmresponder/pdr_utils.hpp"
8 #include "libpldmresponder/platform.hpp"
9 #include "libpldmresponder/platform_numeric_effecter.hpp"
10 #include "libpldmresponder/platform_state_effecter.hpp"
11 #include "libpldmresponder/platform_state_sensor.hpp"
12 
13 #include <sdbusplus/test/sdbus_mock.hpp>
14 #include <sdeventplus/event.hpp>
15 
16 using namespace pldm::pdr;
17 using namespace pldm::utils;
18 using namespace pldm::responder;
19 using namespace pldm::responder::platform;
20 using namespace pldm::responder::pdr;
21 using namespace pldm::responder::pdr_utils;
22 
23 using ::testing::_;
24 using ::testing::Return;
25 using ::testing::StrEq;
26 
27 TEST(getPDR, testGoodPath)
28 {
29     std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_PDR_REQ_BYTES>
30         requestPayload{};
31     auto req = reinterpret_cast<pldm_msg*>(requestPayload.data());
32     size_t requestPayloadLength = requestPayload.size() - sizeof(pldm_msg_hdr);
33 
34     struct pldm_get_pdr_req* request =
35         reinterpret_cast<struct pldm_get_pdr_req*>(req->payload);
36     request->request_count = 100;
37 
38     MockdBusHandler mockedUtils;
39     EXPECT_CALL(mockedUtils, getService(StrEq("/foo/bar"), _))
40         .Times(5)
41         .WillRepeatedly(Return("foo.bar"));
42 
43     auto pdrRepo = pldm_pdr_init();
44     auto event = sdeventplus::Event::get_default();
45     Handler handler(&mockedUtils, 0, nullptr, "./pdr_jsons/state_effecter/good",
46                     pdrRepo, nullptr, nullptr, nullptr, nullptr, nullptr,
47                     event);
48     Repo repo(pdrRepo);
49     ASSERT_EQ(repo.empty(), false);
50     auto response = handler.getPDR(req, requestPayloadLength);
51     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
52 
53     struct pldm_get_pdr_resp* resp =
54         reinterpret_cast<struct pldm_get_pdr_resp*>(responsePtr->payload);
55     ASSERT_EQ(PLDM_SUCCESS, resp->completion_code);
56     ASSERT_EQ(2, resp->next_record_handle);
57     ASSERT_EQ(true, resp->response_count != 0);
58 
59     pldm_pdr_hdr* hdr = reinterpret_cast<pldm_pdr_hdr*>(resp->record_data);
60     ASSERT_EQ(hdr->record_handle, 1);
61     ASSERT_EQ(hdr->version, 1);
62 
63     pldm_pdr_destroy(pdrRepo);
64 }
65 
66 TEST(getPDR, testShortRead)
67 {
68     std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_PDR_REQ_BYTES>
69         requestPayload{};
70     auto req = reinterpret_cast<pldm_msg*>(requestPayload.data());
71     size_t requestPayloadLength = requestPayload.size() - sizeof(pldm_msg_hdr);
72 
73     struct pldm_get_pdr_req* request =
74         reinterpret_cast<struct pldm_get_pdr_req*>(req->payload);
75     request->request_count = 1;
76 
77     MockdBusHandler mockedUtils;
78     EXPECT_CALL(mockedUtils, getService(StrEq("/foo/bar"), _))
79         .Times(5)
80         .WillRepeatedly(Return("foo.bar"));
81 
82     auto pdrRepo = pldm_pdr_init();
83     auto event = sdeventplus::Event::get_default();
84     Handler handler(&mockedUtils, 0, nullptr, "./pdr_jsons/state_effecter/good",
85                     pdrRepo, nullptr, nullptr, nullptr, nullptr, nullptr,
86                     event);
87     Repo repo(pdrRepo);
88     ASSERT_EQ(repo.empty(), false);
89     auto response = handler.getPDR(req, requestPayloadLength);
90     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
91     struct pldm_get_pdr_resp* resp =
92         reinterpret_cast<struct pldm_get_pdr_resp*>(responsePtr->payload);
93     ASSERT_EQ(PLDM_SUCCESS, resp->completion_code);
94     ASSERT_EQ(1, resp->response_count);
95     pldm_pdr_destroy(pdrRepo);
96 }
97 
98 TEST(getPDR, testBadRecordHandle)
99 {
100     std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_PDR_REQ_BYTES>
101         requestPayload{};
102     auto req = reinterpret_cast<pldm_msg*>(requestPayload.data());
103     size_t requestPayloadLength = requestPayload.size() - sizeof(pldm_msg_hdr);
104 
105     struct pldm_get_pdr_req* request =
106         reinterpret_cast<struct pldm_get_pdr_req*>(req->payload);
107     request->record_handle = 100000;
108     request->request_count = 1;
109 
110     MockdBusHandler mockedUtils;
111     EXPECT_CALL(mockedUtils, getService(StrEq("/foo/bar"), _))
112         .Times(5)
113         .WillRepeatedly(Return("foo.bar"));
114 
115     auto pdrRepo = pldm_pdr_init();
116     auto event = sdeventplus::Event::get_default();
117     Handler handler(&mockedUtils, 0, nullptr, "./pdr_jsons/state_effecter/good",
118                     pdrRepo, nullptr, nullptr, nullptr, nullptr, nullptr,
119                     event);
120     Repo repo(pdrRepo);
121     ASSERT_EQ(repo.empty(), false);
122     auto response = handler.getPDR(req, requestPayloadLength);
123     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
124 
125     ASSERT_EQ(responsePtr->payload[0], PLDM_PLATFORM_INVALID_RECORD_HANDLE);
126 
127     pldm_pdr_destroy(pdrRepo);
128 }
129 
130 TEST(getPDR, testNoNextRecord)
131 {
132     std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_PDR_REQ_BYTES>
133         requestPayload{};
134     auto req = reinterpret_cast<pldm_msg*>(requestPayload.data());
135     size_t requestPayloadLength = requestPayload.size() - sizeof(pldm_msg_hdr);
136 
137     struct pldm_get_pdr_req* request =
138         reinterpret_cast<struct pldm_get_pdr_req*>(req->payload);
139     request->record_handle = 1;
140 
141     MockdBusHandler mockedUtils;
142     EXPECT_CALL(mockedUtils, getService(StrEq("/foo/bar"), _))
143         .Times(5)
144         .WillRepeatedly(Return("foo.bar"));
145 
146     auto pdrRepo = pldm_pdr_init();
147     auto event = sdeventplus::Event::get_default();
148     Handler handler(&mockedUtils, 0, nullptr, "./pdr_jsons/state_effecter/good",
149                     pdrRepo, nullptr, nullptr, nullptr, nullptr, nullptr,
150                     event);
151     Repo repo(pdrRepo);
152     ASSERT_EQ(repo.empty(), false);
153     auto response = handler.getPDR(req, requestPayloadLength);
154     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
155     struct pldm_get_pdr_resp* resp =
156         reinterpret_cast<struct pldm_get_pdr_resp*>(responsePtr->payload);
157     ASSERT_EQ(PLDM_SUCCESS, resp->completion_code);
158     ASSERT_EQ(2, resp->next_record_handle);
159 
160     pldm_pdr_destroy(pdrRepo);
161 }
162 
163 TEST(getPDR, testFindPDR)
164 {
165     std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_PDR_REQ_BYTES>
166         requestPayload{};
167     auto req = reinterpret_cast<pldm_msg*>(requestPayload.data());
168     size_t requestPayloadLength = requestPayload.size() - sizeof(pldm_msg_hdr);
169 
170     struct pldm_get_pdr_req* request =
171         reinterpret_cast<struct pldm_get_pdr_req*>(req->payload);
172     request->request_count = 100;
173 
174     MockdBusHandler mockedUtils;
175     EXPECT_CALL(mockedUtils, getService(StrEq("/foo/bar"), _))
176         .Times(5)
177         .WillRepeatedly(Return("foo.bar"));
178 
179     auto pdrRepo = pldm_pdr_init();
180     auto event = sdeventplus::Event::get_default();
181     Handler handler(&mockedUtils, 0, nullptr, "./pdr_jsons/state_effecter/good",
182                     pdrRepo, nullptr, nullptr, nullptr, nullptr, nullptr,
183                     event);
184     Repo repo(pdrRepo);
185     ASSERT_EQ(repo.empty(), false);
186     auto response = handler.getPDR(req, requestPayloadLength);
187 
188     // Let's try to find a PDR of type stateEffecter (= 11) and entity type =
189     // 100
190     bool found = false;
191     uint32_t handle = 0; // start asking for PDRs from recordHandle 0
192     while (!found)
193     {
194         request->record_handle = handle;
195         auto response = handler.getPDR(req, requestPayloadLength);
196         auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
197         struct pldm_get_pdr_resp* resp =
198             reinterpret_cast<struct pldm_get_pdr_resp*>(responsePtr->payload);
199         ASSERT_EQ(PLDM_SUCCESS, resp->completion_code);
200 
201         handle = resp->next_record_handle; // point to the next pdr in case
202                                            // current is not what we want
203 
204         pldm_pdr_hdr* hdr = reinterpret_cast<pldm_pdr_hdr*>(resp->record_data);
205         if (hdr->type == PLDM_STATE_EFFECTER_PDR)
206         {
207             pldm_state_effecter_pdr* pdr =
208                 reinterpret_cast<pldm_state_effecter_pdr*>(resp->record_data);
209             if (pdr->entity_type == 100)
210             {
211                 found = true;
212                 // Rest of the PDR can be accessed as need be
213                 break;
214             }
215         }
216         if (!resp->next_record_handle) // no more records
217         {
218             break;
219         }
220     }
221     ASSERT_EQ(found, true);
222 
223     pldm_pdr_destroy(pdrRepo);
224 }
225 
226 TEST(setStateEffecterStatesHandler, testGoodRequest)
227 {
228     std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_PDR_REQ_BYTES>
229         requestPayload{};
230     auto req = reinterpret_cast<pldm_msg*>(requestPayload.data());
231     size_t requestPayloadLength = requestPayload.size() - sizeof(pldm_msg_hdr);
232 
233     MockdBusHandler mockedUtils;
234     EXPECT_CALL(mockedUtils, getService(StrEq("/foo/bar"), _))
235         .Times(5)
236         .WillRepeatedly(Return("foo.bar"));
237 
238     auto inPDRRepo = pldm_pdr_init();
239     auto outPDRRepo = pldm_pdr_init();
240     Repo outRepo(outPDRRepo);
241     auto event = sdeventplus::Event::get_default();
242     Handler handler(&mockedUtils, 0, nullptr, "./pdr_jsons/state_effecter/good",
243                     inPDRRepo, nullptr, nullptr, nullptr, nullptr, nullptr,
244                     event);
245     handler.getPDR(req, requestPayloadLength);
246     Repo inRepo(inPDRRepo);
247     getRepoByType(inRepo, outRepo, PLDM_STATE_EFFECTER_PDR);
248     pdr_utils::PdrEntry e;
249     auto record1 = pdr::getRecordByHandle(outRepo, 2, e);
250     ASSERT_NE(record1, nullptr);
251     pldm_state_effecter_pdr* pdr =
252         reinterpret_cast<pldm_state_effecter_pdr*>(e.data);
253     EXPECT_EQ(pdr->hdr.type, PLDM_STATE_EFFECTER_PDR);
254 
255     std::vector<set_effecter_state_field> stateField;
256     stateField.push_back({PLDM_REQUEST_SET, 1});
257     stateField.push_back({PLDM_REQUEST_SET, 1});
258     std::string value = "xyz.openbmc_project.Foo.Bar.V1";
259     PropertyValue propertyValue = value;
260 
261     DBusMapping dbusMapping{"/foo/bar", "xyz.openbmc_project.Foo.Bar",
262                             "propertyName", "string"};
263 
264     EXPECT_CALL(mockedUtils, setDbusProperty(dbusMapping, propertyValue))
265         .Times(2);
266     auto rc = platform_state_effecter::setStateEffecterStatesHandler<
267         MockdBusHandler, Handler>(mockedUtils, handler, 0x1, stateField);
268     ASSERT_EQ(rc, 0);
269 
270     pldm_pdr_destroy(inPDRRepo);
271     pldm_pdr_destroy(outPDRRepo);
272 }
273 
274 TEST(setStateEffecterStatesHandler, testBadRequest)
275 {
276     std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_PDR_REQ_BYTES>
277         requestPayload{};
278     auto req = reinterpret_cast<pldm_msg*>(requestPayload.data());
279     size_t requestPayloadLength = requestPayload.size() - sizeof(pldm_msg_hdr);
280 
281     MockdBusHandler mockedUtils;
282     EXPECT_CALL(mockedUtils, getService(StrEq("/foo/bar"), _))
283         .Times(5)
284         .WillRepeatedly(Return("foo.bar"));
285 
286     auto inPDRRepo = pldm_pdr_init();
287     auto outPDRRepo = pldm_pdr_init();
288     Repo outRepo(outPDRRepo);
289     auto event = sdeventplus::Event::get_default();
290     Handler handler(&mockedUtils, 0, nullptr, "./pdr_jsons/state_effecter/good",
291                     inPDRRepo, nullptr, nullptr, nullptr, nullptr, nullptr,
292                     event);
293     handler.getPDR(req, requestPayloadLength);
294     Repo inRepo(inPDRRepo);
295     getRepoByType(inRepo, outRepo, PLDM_STATE_EFFECTER_PDR);
296     pdr_utils::PdrEntry e;
297     auto record1 = pdr::getRecordByHandle(outRepo, 2, e);
298     ASSERT_NE(record1, nullptr);
299     pldm_state_effecter_pdr* pdr =
300         reinterpret_cast<pldm_state_effecter_pdr*>(e.data);
301     EXPECT_EQ(pdr->hdr.type, PLDM_STATE_EFFECTER_PDR);
302 
303     std::vector<set_effecter_state_field> stateField;
304     stateField.push_back({PLDM_REQUEST_SET, 3});
305     stateField.push_back({PLDM_REQUEST_SET, 4});
306 
307     auto rc = platform_state_effecter::setStateEffecterStatesHandler<
308         MockdBusHandler, Handler>(mockedUtils, handler, 0x1, stateField);
309     ASSERT_EQ(rc, PLDM_PLATFORM_SET_EFFECTER_UNSUPPORTED_SENSORSTATE);
310 
311     rc = platform_state_effecter::setStateEffecterStatesHandler<
312         MockdBusHandler, Handler>(mockedUtils, handler, 0x9, stateField);
313     ASSERT_EQ(rc, PLDM_PLATFORM_INVALID_EFFECTER_ID);
314 
315     stateField.push_back({PLDM_REQUEST_SET, 4});
316     rc = platform_state_effecter::setStateEffecterStatesHandler<
317         MockdBusHandler, Handler>(mockedUtils, handler, 0x1, stateField);
318     ASSERT_EQ(rc, PLDM_ERROR_INVALID_DATA);
319 
320     pldm_pdr_destroy(inPDRRepo);
321     pldm_pdr_destroy(outPDRRepo);
322 }
323 
324 TEST(setNumericEffecterValueHandler, testGoodRequest)
325 {
326     MockdBusHandler mockedUtils;
327     EXPECT_CALL(mockedUtils, getService(StrEq("/foo/bar"), _))
328         .Times(5)
329         .WillRepeatedly(Return("foo.bar"));
330 
331     auto inPDRRepo = pldm_pdr_init();
332     auto numericEffecterPdrRepo = pldm_pdr_init();
333     Repo numericEffecterPDRs(numericEffecterPdrRepo);
334     auto event = sdeventplus::Event::get_default();
335     Handler handler(&mockedUtils, 0, nullptr, "./pdr_jsons/state_effecter/good",
336                     inPDRRepo, nullptr, nullptr, nullptr, nullptr, nullptr,
337                     event);
338     Repo inRepo(inPDRRepo);
339     getRepoByType(inRepo, numericEffecterPDRs, PLDM_NUMERIC_EFFECTER_PDR);
340 
341     pdr_utils::PdrEntry e;
342     auto record4 = pdr::getRecordByHandle(numericEffecterPDRs, 4, e);
343     ASSERT_NE(record4, nullptr);
344 
345     pldm_numeric_effecter_value_pdr* pdr =
346         reinterpret_cast<pldm_numeric_effecter_value_pdr*>(e.data);
347     EXPECT_EQ(pdr->hdr.type, PLDM_NUMERIC_EFFECTER_PDR);
348 
349     uint16_t effecterId = 3;
350     uint32_t effecterValue = 2100000000; // 2036-07-18 21:20:00
351     PropertyValue propertyValue = static_cast<uint64_t>(effecterValue);
352 
353     DBusMapping dbusMapping{"/foo/bar", "xyz.openbmc_project.Foo.Bar",
354                             "propertyName", "uint64_t"};
355     EXPECT_CALL(mockedUtils, setDbusProperty(dbusMapping, propertyValue))
356         .Times(1);
357 
358     auto rc = platform_numeric_effecter::setNumericEffecterValueHandler<
359         MockdBusHandler, Handler>(
360         mockedUtils, handler, effecterId, PLDM_EFFECTER_DATA_SIZE_UINT32,
361         reinterpret_cast<uint8_t*>(&effecterValue), 4);
362     ASSERT_EQ(rc, 0);
363 
364     pldm_pdr_destroy(inPDRRepo);
365     pldm_pdr_destroy(numericEffecterPdrRepo);
366 }
367 
368 TEST(setNumericEffecterValueHandler, testBadRequest)
369 {
370     MockdBusHandler mockedUtils;
371     EXPECT_CALL(mockedUtils, getService(StrEq("/foo/bar"), _))
372         .Times(5)
373         .WillRepeatedly(Return("foo.bar"));
374 
375     auto inPDRRepo = pldm_pdr_init();
376     auto numericEffecterPdrRepo = pldm_pdr_init();
377     Repo numericEffecterPDRs(numericEffecterPdrRepo);
378     auto event = sdeventplus::Event::get_default();
379     Handler handler(&mockedUtils, 0, nullptr, "./pdr_jsons/state_effecter/good",
380                     inPDRRepo, nullptr, nullptr, nullptr, nullptr, nullptr,
381                     event);
382     Repo inRepo(inPDRRepo);
383     getRepoByType(inRepo, numericEffecterPDRs, PLDM_NUMERIC_EFFECTER_PDR);
384 
385     pdr_utils::PdrEntry e;
386     auto record4 = pdr::getRecordByHandle(numericEffecterPDRs, 4, e);
387     ASSERT_NE(record4, nullptr);
388 
389     pldm_numeric_effecter_value_pdr* pdr =
390         reinterpret_cast<pldm_numeric_effecter_value_pdr*>(e.data);
391     EXPECT_EQ(pdr->hdr.type, PLDM_NUMERIC_EFFECTER_PDR);
392 
393     uint16_t effecterId = 3;
394     uint64_t effecterValue = 9876543210;
395     auto rc = platform_numeric_effecter::setNumericEffecterValueHandler<
396         MockdBusHandler, Handler>(
397         mockedUtils, handler, effecterId, PLDM_EFFECTER_DATA_SIZE_SINT32,
398         reinterpret_cast<uint8_t*>(&effecterValue), 3);
399     ASSERT_EQ(rc, PLDM_ERROR_INVALID_DATA);
400 
401     pldm_pdr_destroy(inPDRRepo);
402     pldm_pdr_destroy(numericEffecterPdrRepo);
403 }
404 
405 TEST(getNumericEffecterValueHandler, testGoodRequest)
406 {
407     MockdBusHandler mockedUtils;
408     EXPECT_CALL(mockedUtils, getService(StrEq("/foo/bar"), _))
409         .Times(5)
410         .WillRepeatedly(Return("foo.bar"));
411 
412     auto inPDRRepo = pldm_pdr_init();
413     auto numericEffecterPdrRepo = pldm_pdr_init();
414     Repo numericEffecterPDRs(numericEffecterPdrRepo);
415     auto event = sdeventplus::Event::get_default();
416     Handler handler(&mockedUtils, 0, nullptr, "./pdr_jsons/state_effecter/good",
417                     inPDRRepo, nullptr, nullptr, nullptr, nullptr, nullptr,
418                     event);
419     Repo inRepo(inPDRRepo);
420     getRepoByType(inRepo, numericEffecterPDRs, PLDM_NUMERIC_EFFECTER_PDR);
421 
422     pdr_utils::PdrEntry e;
423     auto record4 = pdr::getRecordByHandle(numericEffecterPDRs, 4, e);
424     ASSERT_NE(record4, nullptr);
425 
426     pldm_numeric_effecter_value_pdr* pdr =
427         reinterpret_cast<pldm_numeric_effecter_value_pdr*>(e.data);
428     EXPECT_EQ(pdr->hdr.type, PLDM_NUMERIC_EFFECTER_PDR);
429 
430     uint16_t effecterId = 3;
431 
432     uint8_t effecterDataSize{};
433     pldm::utils::PropertyValue dbusValue;
434     std::string propertyType;
435 
436     // effecterValue return the present numeric setting
437     uint32_t effecterValue = 2100000000;
438     using effecterOperationalState = uint8_t;
439     using completionCode = uint8_t;
440 
441     EXPECT_CALL(mockedUtils,
442                 getDbusPropertyVariant(StrEq("/foo/bar"), StrEq("propertyName"),
443                                        StrEq("xyz.openbmc_project.Foo.Bar")))
444         .WillOnce(Return(PropertyValue(static_cast<uint64_t>(effecterValue))));
445 
446     auto rc = platform_numeric_effecter::getNumericEffecterData<
447         MockdBusHandler, Handler>(mockedUtils, handler, effecterId,
448                                   effecterDataSize, propertyType, dbusValue);
449 
450     ASSERT_EQ(rc, 0);
451 
452     size_t responsePayloadLength =
453         sizeof(completionCode) + sizeof(effecterDataSize) +
454         sizeof(effecterOperationalState) +
455         getEffecterDataSize(effecterDataSize) +
456         getEffecterDataSize(effecterDataSize);
457 
458     Response response(responsePayloadLength + sizeof(pldm_msg_hdr));
459     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
460 
461     rc = platform_numeric_effecter::getNumericEffecterValueHandler(
462         propertyType, dbusValue, effecterDataSize, responsePtr,
463         responsePayloadLength, 1);
464 
465     ASSERT_EQ(rc, 0);
466 
467     struct pldm_get_numeric_effecter_value_resp* resp =
468         reinterpret_cast<struct pldm_get_numeric_effecter_value_resp*>(
469             responsePtr->payload);
470     ASSERT_EQ(PLDM_SUCCESS, resp->completion_code);
471     uint32_t valPresent;
472     memcpy(&valPresent, &resp->pending_and_present_values[4],
473            sizeof(valPresent));
474 
475     ASSERT_EQ(effecterValue, valPresent);
476 
477     pldm_pdr_destroy(inPDRRepo);
478     pldm_pdr_destroy(numericEffecterPdrRepo);
479 }
480 
481 TEST(getNumericEffecterValueHandler, testBadRequest)
482 {
483     MockdBusHandler mockedUtils;
484     EXPECT_CALL(mockedUtils, getService(StrEq("/foo/bar"), _))
485         .Times(5)
486         .WillRepeatedly(Return("foo.bar"));
487 
488     auto inPDRRepo = pldm_pdr_init();
489     auto numericEffecterPdrRepo = pldm_pdr_init();
490     Repo numericEffecterPDRs(numericEffecterPdrRepo);
491     auto event = sdeventplus::Event::get_default();
492     Handler handler(&mockedUtils, 0, nullptr, "./pdr_jsons/state_effecter/good",
493                     inPDRRepo, nullptr, nullptr, nullptr, nullptr, nullptr,
494                     event);
495     Repo inRepo(inPDRRepo);
496     getRepoByType(inRepo, numericEffecterPDRs, PLDM_NUMERIC_EFFECTER_PDR);
497 
498     pdr_utils::PdrEntry e;
499     auto record4 = pdr::getRecordByHandle(numericEffecterPDRs, 4, e);
500     ASSERT_NE(record4, nullptr);
501 
502     pldm_numeric_effecter_value_pdr* pdr =
503         reinterpret_cast<pldm_numeric_effecter_value_pdr*>(e.data);
504     EXPECT_EQ(pdr->hdr.type, PLDM_NUMERIC_EFFECTER_PDR);
505 
506     uint16_t effecterId = 4;
507 
508     uint8_t effecterDataSize{};
509     pldm::utils::PropertyValue dbusValue;
510     std::string propertyType;
511 
512     auto rc = platform_numeric_effecter::getNumericEffecterData<
513         MockdBusHandler, Handler>(mockedUtils, handler, effecterId,
514                                   effecterDataSize, propertyType, dbusValue);
515 
516     ASSERT_EQ(rc, 128);
517 
518     pldm_pdr_destroy(inPDRRepo);
519     pldm_pdr_destroy(numericEffecterPdrRepo);
520 }
521 
522 TEST(parseStateSensor, allScenarios)
523 {
524     // Sample state sensor with SensorID - 1, EntityType - Processor Module(67)
525     // State Set ID - Operational Running Status(11), Supported States - 3,4
526     std::vector<uint8_t> sample1PDR{
527         0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x17,
528         0x00, 0x00, 0x00, 0x01, 0x00, 0x43, 0x00, 0x01, 0x00,
529         0x00, 0x00, 0x00, 0x00, 0x01, 0x0b, 0x00, 0x01, 0x18};
530 
531     const auto& [terminusHandle1, sensorID1, sensorInfo1] =
532         parseStateSensorPDR(sample1PDR);
533     const auto& [containerID1, entityType1, entityInstance1] =
534         std::get<0>(sensorInfo1);
535     const auto& states1 = std::get<1>(sensorInfo1);
536     CompositeSensorStates statesCmp1{{3u, 4u}};
537 
538     ASSERT_EQ(le16toh(terminusHandle1), 0u);
539     ASSERT_EQ(le16toh(sensorID1), 1u);
540     ASSERT_EQ(le16toh(containerID1), 0u);
541     ASSERT_EQ(le16toh(entityType1), 67u);
542     ASSERT_EQ(le16toh(entityInstance1), 1u);
543     ASSERT_EQ(states1, statesCmp1);
544 
545     // Sample state sensor with SensorID - 2, EntityType - System Firmware(31)
546     // State Set ID - Availability(2), Supported States - 3,4,9,10,11,13
547     std::vector<uint8_t> sample2PDR{
548         0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x17, 0x00,
549         0x00, 0x00, 0x02, 0x00, 0x1F, 0x00, 0x01, 0x00, 0x00, 0x00,
550         0x00, 0x00, 0x01, 0x02, 0x00, 0x02, 0x18, 0x2E};
551 
552     const auto& [terminusHandle2, sensorID2, sensorInfo2] =
553         parseStateSensorPDR(sample2PDR);
554     const auto& [containerID2, entityType2, entityInstance2] =
555         std::get<0>(sensorInfo2);
556     const auto& states2 = std::get<1>(sensorInfo2);
557     CompositeSensorStates statesCmp2{{3u, 4u, 9u, 10u, 11u, 13u}};
558 
559     ASSERT_EQ(le16toh(terminusHandle2), 0u);
560     ASSERT_EQ(le16toh(sensorID2), 2u);
561     ASSERT_EQ(le16toh(containerID2), 0u);
562     ASSERT_EQ(le16toh(entityType2), 31u);
563     ASSERT_EQ(le16toh(entityInstance2), 1u);
564     ASSERT_EQ(states2, statesCmp2);
565 
566     // Sample state sensor with SensorID - 3, EntityType - Virtual Machine
567     // Manager(33), Composite State Sensor -2 , State Set ID - Link State(33),
568     // Supported States - 1,2, State Set ID - Configuration State(15),
569     // Supported States - 1,2,3,4
570     std::vector<uint8_t> sample3PDR{
571         0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x17, 0x00, 0x00,
572         0x00, 0x03, 0x00, 0x21, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00,
573         0x02, 0x21, 0x00, 0x01, 0x06, 0x0F, 0x00, 0x01, 0x1E};
574 
575     const auto& [terminusHandle3, sensorID3, sensorInfo3] =
576         parseStateSensorPDR(sample3PDR);
577     const auto& [containerID3, entityType3, entityInstance3] =
578         std::get<0>(sensorInfo3);
579     const auto& states3 = std::get<1>(sensorInfo3);
580     CompositeSensorStates statesCmp3{{1u, 2u}, {1u, 2u, 3u, 4u}};
581 
582     ASSERT_EQ(le16toh(terminusHandle3), 0u);
583     ASSERT_EQ(le16toh(sensorID3), 3u);
584     ASSERT_EQ(le16toh(containerID3), 1u);
585     ASSERT_EQ(le16toh(entityType3), 33u);
586     ASSERT_EQ(le16toh(entityInstance3), 2u);
587     ASSERT_EQ(states3, statesCmp3);
588 }
589 
590 TEST(StateSensorHandler, allScenarios)
591 {
592     using namespace pldm::responder::events;
593 
594     StateSensorHandler handler{"./event_jsons/good"};
595     constexpr uint8_t eventState0 = 0;
596     constexpr uint8_t eventState1 = 1;
597     constexpr uint8_t eventState2 = 2;
598     constexpr uint8_t eventState3 = 3;
599 
600     // Event Entry 1
601     {
602         StateSensorEntry entry{1, 64, 1, 0, 1, false};
603         const auto& [dbusMapping, eventStateMap] = handler.getEventInfo(entry);
604         DBusMapping mapping{"/xyz/abc/def",
605                             "xyz.openbmc_project.example1.value", "value1",
606                             "string"};
607         ASSERT_EQ(mapping == dbusMapping, true);
608 
609         const auto& propValue0 = eventStateMap.at(eventState0);
610         const auto& propValue1 = eventStateMap.at(eventState1);
611         const auto& propValue2 = eventStateMap.at(eventState2);
612         PropertyValue value0{std::in_place_type<std::string>,
613                              "xyz.openbmc_project.State.Normal"};
614         PropertyValue value1{std::in_place_type<std::string>,
615                              "xyz.openbmc_project.State.Critical"};
616         PropertyValue value2{std::in_place_type<std::string>,
617                              "xyz.openbmc_project.State.Fatal"};
618         ASSERT_EQ(value0 == propValue0, true);
619         ASSERT_EQ(value1 == propValue1, true);
620         ASSERT_EQ(value2 == propValue2, true);
621     }
622 
623     // Event Entry 2
624     {
625         StateSensorEntry entry{1, 64, 1, 1, 1, false};
626         const auto& [dbusMapping, eventStateMap] = handler.getEventInfo(entry);
627         DBusMapping mapping{"/xyz/abc/def",
628                             "xyz.openbmc_project.example2.value", "value2",
629                             "uint8_t"};
630         ASSERT_EQ(mapping == dbusMapping, true);
631 
632         const auto& propValue0 = eventStateMap.at(eventState2);
633         const auto& propValue1 = eventStateMap.at(eventState3);
634         PropertyValue value0{std::in_place_type<uint8_t>, 9};
635         PropertyValue value1{std::in_place_type<uint8_t>, 10};
636         ASSERT_EQ(value0 == propValue0, true);
637         ASSERT_EQ(value1 == propValue1, true);
638     }
639 
640     // Event Entry 3
641     {
642         StateSensorEntry entry{2, 67, 2, 0, 1, false};
643         const auto& [dbusMapping, eventStateMap] = handler.getEventInfo(entry);
644         DBusMapping mapping{"/xyz/abc/ghi",
645                             "xyz.openbmc_project.example3.value", "value3",
646                             "bool"};
647         ASSERT_EQ(mapping == dbusMapping, true);
648 
649         const auto& propValue0 = eventStateMap.at(eventState0);
650         const auto& propValue1 = eventStateMap.at(eventState1);
651         PropertyValue value0{std::in_place_type<bool>, false};
652         PropertyValue value1{std::in_place_type<bool>, true};
653         ASSERT_EQ(value0 == propValue0, true);
654         ASSERT_EQ(value1 == propValue1, true);
655     }
656 
657     // Event Entry 4
658     {
659         StateSensorEntry entry{2, 67, 2, 0, 2, false};
660         const auto& [dbusMapping, eventStateMap] = handler.getEventInfo(entry);
661         DBusMapping mapping{"/xyz/abc/jkl",
662                             "xyz.openbmc_project.example4.value", "value4",
663                             "string"};
664         ASSERT_EQ(mapping == dbusMapping, true);
665 
666         const auto& propValue0 = eventStateMap.at(eventState0);
667         const auto& propValue1 = eventStateMap.at(eventState1);
668         const auto& propValue2 = eventStateMap.at(eventState2);
669         PropertyValue value0{std::in_place_type<std::string>, "Enabled"};
670         PropertyValue value1{std::in_place_type<std::string>, "Disabled"};
671         PropertyValue value2{std::in_place_type<std::string>, "Auto"};
672         ASSERT_EQ(value0 == propValue0, true);
673         ASSERT_EQ(value1 == propValue1, true);
674         ASSERT_EQ(value2 == propValue2, true);
675     }
676 
677     // Event Entry 5
678     {
679         StateSensorEntry entry{0xFFFF, 120, 2, 0, 2, true};
680         const auto& [dbusMapping, eventStateMap] = handler.getEventInfo(entry);
681         DBusMapping mapping{"/xyz/abc/mno",
682                             "xyz.openbmc_project.example5.value", "value5",
683                             "string"};
684         ASSERT_EQ(mapping == dbusMapping, true);
685 
686         const auto& propValue0 = eventStateMap.at(eventState0);
687         const auto& propValue1 = eventStateMap.at(eventState1);
688         const auto& propValue2 = eventStateMap.at(eventState2);
689         PropertyValue value0{std::in_place_type<std::string>, "Enabled"};
690         PropertyValue value1{std::in_place_type<std::string>, "Disabled"};
691         PropertyValue value2{std::in_place_type<std::string>, "Auto"};
692         ASSERT_EQ(value0 == propValue0, true);
693         ASSERT_EQ(value1 == propValue1, true);
694         ASSERT_EQ(value2 == propValue2, true);
695     }
696     // Event Entry 6
697     {
698         StateSensorEntry entry{10, 120, 2, 0, 2, true};
699         const auto& [dbusMapping, eventStateMap] = handler.getEventInfo(entry);
700         DBusMapping mapping{"/xyz/abc/opk",
701                             "xyz.openbmc_project.example6.value", "value6",
702                             "string"};
703         ASSERT_EQ(mapping == dbusMapping, true);
704 
705         const auto& propValue0 = eventStateMap.at(eventState0);
706         const auto& propValue1 = eventStateMap.at(eventState1);
707         const auto& propValue2 = eventStateMap.at(eventState2);
708         PropertyValue value0{std::in_place_type<std::string>, "Enabled"};
709         PropertyValue value1{std::in_place_type<std::string>, "Disabled"};
710         PropertyValue value2{std::in_place_type<std::string>, "Auto"};
711         ASSERT_EQ(value0 == propValue0, true);
712         ASSERT_EQ(value1 == propValue1, true);
713         ASSERT_EQ(value2 == propValue2, true);
714     }
715     // Event Entry 7
716     {
717         StateSensorEntry entry{10, 120, 2, 0, 2, false};
718         const auto& [dbusMapping, eventStateMap] = handler.getEventInfo(entry);
719         DBusMapping mapping{"/xyz/abc/opk",
720                             "xyz.openbmc_project.example6.value", "value6",
721                             "string"};
722         ASSERT_EQ(mapping == dbusMapping, true);
723 
724         const auto& propValue0 = eventStateMap.at(eventState0);
725         const auto& propValue1 = eventStateMap.at(eventState1);
726         const auto& propValue2 = eventStateMap.at(eventState2);
727         PropertyValue value0{std::in_place_type<std::string>, "Enabled"};
728         PropertyValue value1{std::in_place_type<std::string>, "Disabled"};
729         PropertyValue value2{std::in_place_type<std::string>, "Auto"};
730         ASSERT_EQ(value0 == propValue0, true);
731         ASSERT_EQ(value1 == propValue1, true);
732         ASSERT_EQ(value2 == propValue2, true);
733     }
734 
735     // Invalid Entry
736     {
737         StateSensorEntry entry{0, 0, 0, 0, 1, false};
738         ASSERT_THROW(handler.getEventInfo(entry), std::out_of_range);
739     }
740 }
741 
742 TEST(TerminusLocatorPDR, BMCTerminusLocatorPDR)
743 {
744     auto inPDRRepo = pldm_pdr_init();
745     auto outPDRRepo = pldm_pdr_init();
746     Repo outRepo(outPDRRepo);
747     MockdBusHandler mockedUtils;
748     auto event = sdeventplus::Event::get_default();
749     Handler handler(&mockedUtils, 0, nullptr, "", inPDRRepo, nullptr, nullptr,
750                     nullptr, nullptr, nullptr, event);
751     Repo inRepo(inPDRRepo);
752     getRepoByType(inRepo, outRepo, PLDM_TERMINUS_LOCATOR_PDR);
753 
754     // 1 BMC terminus locator PDR in the PDR repository
755     ASSERT_EQ(outRepo.getRecordCount(), 1);
756 
757     pdr_utils::PdrEntry entry;
758     auto record = pdr::getRecordByHandle(outRepo, 1, entry);
759     ASSERT_NE(record, nullptr);
760 
761     auto pdr = reinterpret_cast<const pldm_terminus_locator_pdr*>(entry.data);
762     EXPECT_EQ(pdr->hdr.record_handle, 1);
763     EXPECT_EQ(pdr->hdr.version, 1);
764     EXPECT_EQ(pdr->hdr.type, PLDM_TERMINUS_LOCATOR_PDR);
765     EXPECT_EQ(pdr->hdr.record_change_num, 0);
766     EXPECT_EQ(pdr->hdr.length,
767               sizeof(pldm_terminus_locator_pdr) - sizeof(pldm_pdr_hdr));
768     EXPECT_EQ(pdr->terminus_handle, TERMINUS_HANDLE);
769     EXPECT_EQ(pdr->validity, PLDM_TL_PDR_VALID);
770     EXPECT_EQ(pdr->tid, TERMINUS_ID);
771     EXPECT_EQ(pdr->container_id, 0);
772     EXPECT_EQ(pdr->terminus_locator_type, PLDM_TERMINUS_LOCATOR_TYPE_MCTP_EID);
773     EXPECT_EQ(pdr->terminus_locator_value_size,
774               sizeof(pldm_terminus_locator_type_mctp_eid));
775     auto locatorValue =
776         reinterpret_cast<const pldm_terminus_locator_type_mctp_eid*>(
777             pdr->terminus_locator_value);
778     EXPECT_EQ(locatorValue->eid, pldm::BmcMctpEid);
779     pldm_pdr_destroy(inPDRRepo);
780     pldm_pdr_destroy(outPDRRepo);
781 }
782 
783 TEST(getStateSensorReadingsHandler, testGoodRequest)
784 {
785     MockdBusHandler mockedUtils;
786     EXPECT_CALL(mockedUtils, getService(StrEq("/foo/bar"), _))
787         .Times(1)
788         .WillRepeatedly(Return("foo.bar"));
789 
790     auto inPDRRepo = pldm_pdr_init();
791     auto outPDRRepo = pldm_pdr_init();
792     Repo outRepo(outPDRRepo);
793     auto event = sdeventplus::Event::get_default();
794     Handler handler(&mockedUtils, 0, nullptr, "./pdr_jsons/state_sensor/good",
795                     inPDRRepo, nullptr, nullptr, nullptr, nullptr, nullptr,
796                     event);
797     Repo inRepo(inPDRRepo);
798     getRepoByType(inRepo, outRepo, PLDM_STATE_SENSOR_PDR);
799     pdr_utils::PdrEntry e;
800     auto record = pdr::getRecordByHandle(outRepo, 2, e);
801     ASSERT_NE(record, nullptr);
802     pldm_state_sensor_pdr* pdr =
803         reinterpret_cast<pldm_state_sensor_pdr*>(e.data);
804     EXPECT_EQ(pdr->hdr.type, PLDM_STATE_SENSOR_PDR);
805 
806     std::vector<get_sensor_state_field> stateField;
807     uint8_t compSensorCnt{};
808     uint8_t sensorRearmCnt = 1;
809 
810     MockdBusHandler handlerObj;
811     EXPECT_CALL(handlerObj,
812                 getDbusPropertyVariant(StrEq("/foo/bar"), StrEq("propertyName"),
813                                        StrEq("xyz.openbmc_project.Foo.Bar")))
814         .WillOnce(Return(
815             PropertyValue(std::string("xyz.openbmc_project.Foo.Bar.V0"))));
816     EventStates cache = {PLDM_SENSOR_NORMAL};
817     pldm::stateSensorCacheMaps sensorCache;
818     sensorCache.emplace(0x1, cache);
819     auto rc = platform_state_sensor::getStateSensorReadingsHandler<
820         MockdBusHandler, Handler>(handlerObj, handler, 0x1, sensorRearmCnt,
821                                   compSensorCnt, stateField, sensorCache);
822     ASSERT_EQ(rc, 0);
823     ASSERT_EQ(compSensorCnt, 1);
824     ASSERT_EQ(stateField[0].sensor_op_state, PLDM_SENSOR_UNAVAILABLE);
825     ASSERT_EQ(stateField[0].present_state, PLDM_SENSOR_NORMAL);
826     ASSERT_EQ(stateField[0].previous_state, PLDM_SENSOR_NORMAL);
827     ASSERT_EQ(stateField[0].event_state, PLDM_SENSOR_UNKNOWN);
828 
829     pldm_pdr_destroy(inPDRRepo);
830     pldm_pdr_destroy(outPDRRepo);
831 }
832 
833 TEST(getStateSensorReadingsHandler, testBadRequest)
834 {
835     MockdBusHandler mockedUtils;
836     EXPECT_CALL(mockedUtils, getService(StrEq("/foo/bar"), _))
837         .Times(1)
838         .WillRepeatedly(Return("foo.bar"));
839 
840     auto inPDRRepo = pldm_pdr_init();
841     auto outPDRRepo = pldm_pdr_init();
842     Repo outRepo(outPDRRepo);
843     auto event = sdeventplus::Event::get_default();
844     Handler handler(&mockedUtils, 0, nullptr, "./pdr_jsons/state_sensor/good",
845                     inPDRRepo, nullptr, nullptr, nullptr, nullptr, nullptr,
846                     event);
847     Repo inRepo(inPDRRepo);
848     getRepoByType(inRepo, outRepo, PLDM_STATE_SENSOR_PDR);
849     pdr_utils::PdrEntry e;
850     auto record = pdr::getRecordByHandle(outRepo, 2, e);
851     ASSERT_NE(record, nullptr);
852     pldm_state_sensor_pdr* pdr =
853         reinterpret_cast<pldm_state_sensor_pdr*>(e.data);
854     EXPECT_EQ(pdr->hdr.type, PLDM_STATE_SENSOR_PDR);
855 
856     std::vector<get_sensor_state_field> stateField;
857     uint8_t compSensorCnt{};
858     uint8_t sensorRearmCnt = 3;
859 
860     MockdBusHandler handlerObj;
861     EventStates cache = {PLDM_SENSOR_NORMAL};
862     pldm::stateSensorCacheMaps sensorCache;
863     sensorCache.emplace(0x1, cache);
864     auto rc = platform_state_sensor::getStateSensorReadingsHandler<
865         MockdBusHandler, Handler>(handlerObj, handler, 0x1, sensorRearmCnt,
866                                   compSensorCnt, stateField, sensorCache);
867     ASSERT_EQ(rc, PLDM_PLATFORM_REARM_UNAVAILABLE_IN_PRESENT_STATE);
868 
869     pldm_pdr_destroy(inPDRRepo);
870     pldm_pdr_destroy(outPDRRepo);
871 }
872