1 #include "nlohmann/json.hpp"
2 #include "rde/external_storer_interface.hpp"
3 #include "rde/rde_handler.hpp"
4
5 #include <memory>
6 #include <span>
7
8 #include <gmock/gmock-matchers.h>
9 #include <gmock/gmock.h>
10 #include <gtest/gtest.h>
11
12 namespace bios_bmc_smm_error_logger
13 {
14 namespace rde
15 {
16
17 using ::testing::Return;
18
19 /**
20 * @brief Dummy values for annotation dictionary. We do not need the annotation
21 * dictionary. So this contains a dictionary with some dummy values. But the RDE
22 * header is correct.
23 */
24 constexpr std::array<uint8_t, 38> mRcvDummyAnnotation{
25 {0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
26 0x0, 0x0, 0xc, 0x0, 0x0, 0xf0, 0xf0, 0xf1, 0x17, 0x1,
27 0x0, 0x0, 0x0, 0x0, 0x0, 0x16, 0x0, 0x5, 0x0, 0xc,
28 0x84, 0x0, 0x14, 0x0, 0x30, 0xa8, 0xc3, 0x3c}};
29
30 constexpr std::array<uint8_t, 38> mRcvDummyInvalidChecksum{
31 {0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
32 0x0, 0x0, 0xc, 0x0, 0x0, 0xf0, 0xf0, 0xf1, 0x17, 0x1,
33 0x0, 0x0, 0x0, 0x0, 0x0, 0x16, 0x0, 0x5, 0x0, 0xc,
34 0x84, 0x0, 0x14, 0x0, 0x17, 0x86, 0x00, 0x00}};
35
36 /**
37 * @brief MultipartReceive command with START_AND_END flag set.
38 */
39 constexpr std::array<uint8_t, 293> mRcvInput0StartAndEnd{
40 {0x00, 0x03, 0x02, 0x00, 0x00, 0x00, 0x17, 0x01, 0x00, 0x00, 0x0, 0x0,
41 0xc, 0x0, 0x0, 0xf0, 0xf0, 0xf1, 0x17, 0x1, 0x0, 0x0, 0x0, 0x0,
42 0x0, 0x16, 0x0, 0x5, 0x0, 0xc, 0x84, 0x0, 0x14, 0x0, 0x0, 0x48,
43 0x0, 0x1, 0x0, 0x13, 0x90, 0x0, 0x56, 0x1, 0x0, 0x0, 0x0, 0x0,
44 0x0, 0x3, 0xa3, 0x0, 0x74, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x16,
45 0xa6, 0x0, 0x34, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x16, 0xbc, 0x0,
46 0x64, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x13, 0xd2, 0x0, 0x0, 0x0,
47 0x0, 0x52, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x74, 0x0, 0x0, 0x0,
48 0x0, 0x0, 0x0, 0xf, 0xe5, 0x0, 0x46, 0x1, 0x0, 0x66, 0x0, 0x3,
49 0x0, 0xb, 0xf4, 0x0, 0x50, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9,
50 0xff, 0x0, 0x50, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0x8, 0x1,
51 0x50, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xf, 0x1, 0x44, 0x75,
52 0x6d, 0x6d, 0x79, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x0, 0x43, 0x68,
53 0x69, 0x6c, 0x64, 0x41, 0x72, 0x72, 0x61, 0x79, 0x50, 0x72, 0x6f, 0x70,
54 0x65, 0x72, 0x74, 0x79, 0x0, 0x49, 0x64, 0x0, 0x53, 0x61, 0x6d, 0x70,
55 0x6c, 0x65, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x50, 0x72, 0x6f,
56 0x70, 0x65, 0x72, 0x74, 0x79, 0x0, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65,
57 0x49, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x70, 0x65,
58 0x72, 0x74, 0x79, 0x0, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x52, 0x65,
59 0x61, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x0, 0x41,
60 0x6e, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x42, 0x6f, 0x6f, 0x6c, 0x65, 0x61,
61 0x6e, 0x0, 0x4c, 0x69, 0x6e, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
62 0x0, 0x4c, 0x69, 0x6e, 0x6b, 0x44, 0x6f, 0x77, 0x6e, 0x0, 0x4c, 0x69,
63 0x6e, 0x6b, 0x55, 0x70, 0x0, 0x4e, 0x6f, 0x4c, 0x69, 0x6e, 0x6b, 0x0,
64 0x0, 0x8c, 0x87, 0xed, 0x74}};
65
66 /**
67 * @brief MultipartReceive command with START flag set.
68 */
69 constexpr std::array<uint8_t, 166> mRcvInput1Start{
70 {0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x0, 0x0,
71 0xc, 0x0, 0x0, 0xf0, 0xf0, 0xf1, 0x17, 0x1, 0x0, 0x0, 0x0, 0x0,
72 0x0, 0x16, 0x0, 0x5, 0x0, 0xc, 0x84, 0x0, 0x14, 0x0, 0x0, 0x48,
73 0x0, 0x1, 0x0, 0x13, 0x90, 0x0, 0x56, 0x1, 0x0, 0x0, 0x0, 0x0,
74 0x0, 0x3, 0xa3, 0x0, 0x74, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x16,
75 0xa6, 0x0, 0x34, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x16, 0xbc, 0x0,
76 0x64, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x13, 0xd2, 0x0, 0x0, 0x0,
77 0x0, 0x52, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x74, 0x0, 0x0, 0x0,
78 0x0, 0x0, 0x0, 0xf, 0xe5, 0x0, 0x46, 0x1, 0x0, 0x66, 0x0, 0x3,
79 0x0, 0xb, 0xf4, 0x0, 0x50, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9,
80 0xff, 0x0, 0x50, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0x8, 0x1,
81 0x50, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xf, 0x1, 0x44, 0x75,
82 0x6d, 0x6d, 0x79, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x0, 0x43, 0x68,
83 0x69, 0x6c, 0x64, 0x41, 0x72, 0x72, 0x61, 0x79, 0x50, 0x72}};
84
85 /**
86 * @brief MultipartReceive command with END flag set.
87 */
88 constexpr std::array<uint8_t, 137> mRcvInput1End{
89 {0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x6f, 0x70,
90 0x65, 0x72, 0x74, 0x79, 0x0, 0x49, 0x64, 0x0, 0x53, 0x61, 0x6d, 0x70,
91 0x6c, 0x65, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x50, 0x72, 0x6f,
92 0x70, 0x65, 0x72, 0x74, 0x79, 0x0, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65,
93 0x49, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x70, 0x65,
94 0x72, 0x74, 0x79, 0x0, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x52, 0x65,
95 0x61, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x0, 0x41,
96 0x6e, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x42, 0x6f, 0x6f, 0x6c, 0x65, 0x61,
97 0x6e, 0x0, 0x4c, 0x69, 0x6e, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
98 0x0, 0x4c, 0x69, 0x6e, 0x6b, 0x44, 0x6f, 0x77, 0x6e, 0x0, 0x4c, 0x69,
99 0x6e, 0x6b, 0x55, 0x70, 0x0, 0x4e, 0x6f, 0x4c, 0x69, 0x6e, 0x6b, 0x0,
100 0x0, 0x8c, 0x87, 0xed, 0x74}};
101
102 /**
103 * @brief MultipartReceive command with START flag set.
104 */
105 constexpr std::array<uint8_t, 106> mRcvInput2Start{
106 {0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x60, 0x0, 0x00, 0x00, 0x0, 0x0,
107 0xc, 0x0, 0x0, 0xf0, 0xf0, 0xf1, 0x17, 0x1, 0x0, 0x0, 0x0, 0x0,
108 0x0, 0x16, 0x0, 0x5, 0x0, 0xc, 0x84, 0x0, 0x14, 0x0, 0x0, 0x48,
109 0x0, 0x1, 0x0, 0x13, 0x90, 0x0, 0x56, 0x1, 0x0, 0x0, 0x0, 0x0,
110 0x0, 0x3, 0xa3, 0x0, 0x74, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x16,
111 0xa6, 0x0, 0x34, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x16, 0xbc, 0x0,
112 0x64, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x13, 0xd2, 0x0, 0x0, 0x0,
113 0x0, 0x52, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x74, 0x0, 0x0, 0x0,
114 0x0, 0x0, 0x0, 0xf, 0xe5, 0x0, 0x46, 0x1, 0x0, 0x66}};
115
116 /**
117 * @brief MultipartReceive command with MIDDLE flag set.
118 */
119 constexpr std::array<uint8_t, 106> mRcvInput2Mid{
120 {0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x60, 0x0, 0x00, 0x00, 0x0, 0x3,
121 0x0, 0xb, 0xf4, 0x0, 0x50, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9,
122 0xff, 0x0, 0x50, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0x8, 0x1,
123 0x50, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xf, 0x1, 0x44, 0x75,
124 0x6d, 0x6d, 0x79, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x0, 0x43, 0x68,
125 0x69, 0x6c, 0x64, 0x41, 0x72, 0x72, 0x61, 0x79, 0x50, 0x72, 0x6f, 0x70,
126 0x65, 0x72, 0x74, 0x79, 0x0, 0x49, 0x64, 0x0, 0x53, 0x61, 0x6d, 0x70,
127 0x6c, 0x65, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x50, 0x72, 0x6f,
128 0x70, 0x65, 0x72, 0x74, 0x79, 0x0, 0x53, 0x61, 0x6d, 0x70}};
129
130 /**
131 * @brief MultipartReceive command with END flag set.
132 */
133 constexpr std::array<uint8_t, 101> mRcvInput2End{
134 {0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x57, 0x0, 0x00, 0x00, 0x6c, 0x65,
135 0x49, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x70, 0x65,
136 0x72, 0x74, 0x79, 0x0, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x52, 0x65,
137 0x61, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x0, 0x41,
138 0x6e, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x42, 0x6f, 0x6f, 0x6c, 0x65, 0x61,
139 0x6e, 0x0, 0x4c, 0x69, 0x6e, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
140 0x0, 0x4c, 0x69, 0x6e, 0x6b, 0x44, 0x6f, 0x77, 0x6e, 0x0, 0x4c, 0x69,
141 0x6e, 0x6b, 0x55, 0x70, 0x0, 0x4e, 0x6f, 0x4c, 0x69, 0x6e, 0x6b, 0x0,
142 0x0, 0x8c, 0x87, 0xed, 0x74}};
143
144 /**
145 * @brief RDEOperationInit command with encoded json/dummysimple.json as the
146 * payload.
147 */
148 constexpr std::array<uint8_t, 113> mInitOp{
149 {0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00,
150 0x00, 0x60, 0x00, 0x00, 0x00, 0x0, 0xf0, 0xf0, 0xf1, 0x0, 0x0, 0x0,
151 0x1, 0x0, 0x0, 0x1, 0x54, 0x1, 0x5, 0x1, 0x2, 0x50, 0x1, 0x9,
152 0x44, 0x75, 0x6d, 0x6d, 0x79, 0x20, 0x49, 0x44, 0x0, 0x1, 0x6, 0x20,
153 0x1, 0x0, 0x1, 0x8, 0x60, 0x1, 0xb, 0x1, 0x2, 0x38, 0xea, 0x1,
154 0x0, 0x2, 0xa3, 0x23, 0x1, 0x0, 0x1, 0x4, 0x70, 0x1, 0x1, 0x0,
155 0x1, 0x0, 0x10, 0x1, 0x24, 0x1, 0x2, 0x1, 0x0, 0x0, 0x1, 0xf,
156 0x1, 0x2, 0x1, 0x0, 0x70, 0x1, 0x1, 0x1, 0x1, 0x2, 0x40, 0x1,
157 0x2, 0x1, 0x2, 0x1, 0x2, 0x0, 0x1, 0x9, 0x1, 0x1, 0x1, 0x2,
158 0x40, 0x1, 0x2, 0x1, 0x2}};
159
160 class MockExternalStorer : public ExternalStorerInterface
161 {
162 public:
163 MOCK_METHOD(bool, publishJson, (std::string_view jsonStr), (override));
164 };
165
166 class RdeHandlerTest : public ::testing::Test
167 {
168 public:
RdeHandlerTest()169 RdeHandlerTest() : mockExStorer(std::make_unique<MockExternalStorer>())
170 {
171 mockExStorerPtr = dynamic_cast<MockExternalStorer*>(mockExStorer.get());
172 rdeH = std::make_unique<RdeCommandHandler>(std::move(mockExStorer));
173 }
174
175 protected:
176 std::unique_ptr<ExternalStorerInterface> mockExStorer;
177 std::unique_ptr<RdeCommandHandler> rdeH;
178 MockExternalStorer* mockExStorerPtr;
179 const std::string exJson =
180 R"({"Id":"Dummy ID","SampleIntegerProperty":null,"SampleRealProperty":-5576.9123,"SampleEnabledProperty":false,"ChildArrayProperty":[{"AnotherBoolean":true,"LinkStatus":"NoLink"},{"LinkStatus":"NoLink"}]})";
181 };
182
TEST_F(RdeHandlerTest,DictionaryStartAndEndTest)183 TEST_F(RdeHandlerTest, DictionaryStartAndEndTest)
184 {
185 // Send a payload with START_AND_END flag.
186 EXPECT_THAT(
187 rdeH->decodeRdeCommand(std::span(mRcvInput0StartAndEnd),
188 RdeCommandType::RdeMultiPartReceiveResponse),
189 RdeDecodeStatus::RdeStopFlagReceived);
190 EXPECT_THAT(rdeH->getDictionaryCount(), 1);
191 // Send annotation dictionary.
192 EXPECT_THAT(
193 rdeH->decodeRdeCommand(std::span(mRcvDummyAnnotation),
194 RdeCommandType::RdeMultiPartReceiveResponse),
195 RdeDecodeStatus::RdeStopFlagReceived);
196 EXPECT_THAT(rdeH->getDictionaryCount(), 2);
197
198 // Send the encoded payload.
199 EXPECT_CALL(*mockExStorerPtr, publishJson(exJson)).WillOnce(Return(true));
200 EXPECT_THAT(rdeH->decodeRdeCommand(std::span(mInitOp),
201 RdeCommandType::RdeOperationInitRequest),
202 RdeDecodeStatus::RdeOk);
203 }
204
TEST_F(RdeHandlerTest,DictionaryStartThenEndTest)205 TEST_F(RdeHandlerTest, DictionaryStartThenEndTest)
206 {
207 // Send a payload with START flag.
208 EXPECT_THAT(
209 rdeH->decodeRdeCommand(std::span(mRcvInput1Start),
210 RdeCommandType::RdeMultiPartReceiveResponse),
211 RdeDecodeStatus::RdeOk);
212 // We didn't send END. So dictionary count should be 0.
213 EXPECT_THAT(rdeH->getDictionaryCount(), 0);
214 // Send a payload with END flag.
215 EXPECT_THAT(
216 rdeH->decodeRdeCommand(std::span(mRcvInput1End),
217 RdeCommandType::RdeMultiPartReceiveResponse),
218 RdeDecodeStatus::RdeStopFlagReceived);
219 EXPECT_THAT(rdeH->getDictionaryCount(), 1);
220 // Send annotation dictionary.
221 EXPECT_THAT(
222 rdeH->decodeRdeCommand(std::span(mRcvDummyAnnotation),
223 RdeCommandType::RdeMultiPartReceiveResponse),
224 RdeDecodeStatus::RdeStopFlagReceived);
225 EXPECT_THAT(rdeH->getDictionaryCount(), 2);
226
227 // Send the encoded payload.
228 EXPECT_CALL(*mockExStorerPtr, publishJson(exJson)).WillOnce(Return(true));
229 EXPECT_THAT(rdeH->decodeRdeCommand(std::span(mInitOp),
230 RdeCommandType::RdeOperationInitRequest),
231 RdeDecodeStatus::RdeOk);
232
233 // Sending the START again for same resource ID should decrease the
234 // dictionary count.
235 EXPECT_THAT(
236 rdeH->decodeRdeCommand(std::span(mRcvInput1Start),
237 RdeCommandType::RdeMultiPartReceiveResponse),
238 RdeDecodeStatus::RdeOk);
239 EXPECT_THAT(rdeH->getDictionaryCount(), 1);
240 }
241
TEST_F(RdeHandlerTest,DictionaryStartMidEndTest)242 TEST_F(RdeHandlerTest, DictionaryStartMidEndTest)
243 {
244 // Send a payload with START flag.
245 EXPECT_THAT(
246 rdeH->decodeRdeCommand(std::span(mRcvInput2Start),
247 RdeCommandType::RdeMultiPartReceiveResponse),
248 RdeDecodeStatus::RdeOk);
249 // We didn't send END. So dictionary count should be 0.
250 EXPECT_THAT(rdeH->getDictionaryCount(), 0);
251 // Send a payload with MIDDLE flag.
252 EXPECT_THAT(
253 rdeH->decodeRdeCommand(std::span(mRcvInput2Mid),
254 RdeCommandType::RdeMultiPartReceiveResponse),
255 RdeDecodeStatus::RdeOk);
256 // We didn't send END. So dictionary count should be 0.
257 EXPECT_THAT(rdeH->getDictionaryCount(), 0);
258 // Send a payload with END flag.
259 EXPECT_THAT(
260 rdeH->decodeRdeCommand(std::span(mRcvInput2End),
261 RdeCommandType::RdeMultiPartReceiveResponse),
262 RdeDecodeStatus::RdeStopFlagReceived);
263 EXPECT_THAT(rdeH->getDictionaryCount(), 1);
264
265 // Send annotation dictionary.
266 EXPECT_THAT(
267 rdeH->decodeRdeCommand(std::span(mRcvDummyAnnotation),
268 RdeCommandType::RdeMultiPartReceiveResponse),
269 RdeDecodeStatus::RdeStopFlagReceived);
270 EXPECT_THAT(rdeH->getDictionaryCount(), 2);
271
272 // Send the encoded payload.
273 EXPECT_CALL(*mockExStorerPtr, publishJson(exJson)).WillOnce(Return(true));
274 EXPECT_THAT(rdeH->decodeRdeCommand(std::span(mInitOp),
275 RdeCommandType::RdeOperationInitRequest),
276 RdeDecodeStatus::RdeOk);
277 }
278
TEST_F(RdeHandlerTest,InvalidDictionaryFlowTest)279 TEST_F(RdeHandlerTest, InvalidDictionaryFlowTest)
280 {
281 // Send a payload with MIDDLE flag before START and it should fail.
282 EXPECT_THAT(
283 rdeH->decodeRdeCommand(std::span(mRcvInput2Mid),
284 RdeCommandType::RdeMultiPartReceiveResponse),
285 RdeDecodeStatus::RdeInvalidPktOrder);
286 // Send a payload with END flag before START and it should fail.
287 EXPECT_THAT(
288 rdeH->decodeRdeCommand(std::span(mRcvInput2End),
289 RdeCommandType::RdeMultiPartReceiveResponse),
290 RdeDecodeStatus::RdeInvalidPktOrder);
291 }
292
TEST_F(RdeHandlerTest,MissingDictionaryTest)293 TEST_F(RdeHandlerTest, MissingDictionaryTest)
294 {
295 // Try decoding without any dictionaries.
296 EXPECT_THAT(rdeH->decodeRdeCommand(std::span(mInitOp),
297 RdeCommandType::RdeOperationInitRequest),
298 RdeDecodeStatus::RdeNoDictionary);
299
300 // Try decoding just with annotation dictionary.
301 EXPECT_THAT(
302 rdeH->decodeRdeCommand(std::span(mRcvDummyAnnotation),
303 RdeCommandType::RdeMultiPartReceiveResponse),
304 RdeDecodeStatus::RdeStopFlagReceived);
305 EXPECT_THAT(rdeH->decodeRdeCommand(std::span(mInitOp),
306 RdeCommandType::RdeOperationInitRequest),
307 RdeDecodeStatus::RdeNoDictionary);
308 }
309
TEST_F(RdeHandlerTest,InvalidDictionaryChecksumTest)310 TEST_F(RdeHandlerTest, InvalidDictionaryChecksumTest)
311 {
312 // Send a dictionary with an invalid checksum.
313 EXPECT_THAT(
314 rdeH->decodeRdeCommand(std::span(mRcvDummyInvalidChecksum),
315 RdeCommandType::RdeMultiPartReceiveResponse),
316 RdeDecodeStatus::RdeInvalidChecksum);
317 }
318
319 } // namespace rde
320 } // namespace bios_bmc_smm_error_logger
321