blob: 9240102250737bd741163b5a2e3e7b5812795f42 [file] [log] [blame]
kasunathbac958d2022-06-07 18:15:24 -07001#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
12namespace bios_bmc_smm_error_logger
13{
14namespace rde
15{
16
Brandon Kim90ccfe82025-06-06 20:38:56 +000017using ::testing::_;
18using ::testing::NiceMock;
kasunathbac958d2022-06-07 18:15:24 -070019using ::testing::Return;
20
Brandon Kim90ccfe82025-06-06 20:38:56 +000021// Mock for ExternalStorerInterface
22class MockExternalStorerInterface : public ExternalStorerInterface
23{
24 public:
25 MOCK_METHOD(bool, publishJson, (std::string_view jsonStr), (override));
26};
27
28// Test fixture for RdeCommandHandler
29class RdeCommandHandlerTest : public ::testing::Test
30{
31 protected:
32 std::unique_ptr<MockExternalStorerInterface> mockExStorerInstance;
33 // Note: RdeCommandHandler takes ownership of the raw pointer.
34 // We pass mockExStorerInstance.get() and it's moved into the handler.
35 // For safety in test setup, we'll create the handler with a moved
36 // unique_ptr.
37 std::unique_ptr<RdeCommandHandler> handler;
38
39 void SetUp() override
40 {
41 auto exStorer =
42 std::make_unique<NiceMock<MockExternalStorerInterface>>();
43 // Keep a raw pointer for EXPECT_CALL, but handler owns the unique_ptr
44 mockExStorer = exStorer.get();
45 handler = std::make_unique<RdeCommandHandler>(std::move(exStorer));
46 }
47
48 // Helper to create RdeOperationInitReqHeader and its command data
49 std::vector<uint8_t> createOpInitReqCmd(
50 bool containsPayload, uint8_t opType, uint8_t sendDataTransferHandle,
51 uint32_t resourceID, uint8_t opLocatorLength,
52 uint16_t requestPayloadLength,
53 const std::vector<uint8_t>& payloadData = {})
54 {
55 RdeOperationInitReqHeader header{};
56 header.containsRequestPayload = containsPayload;
57 header.operationType = opType;
58 header.sendDataTransferHandle = sendDataTransferHandle;
59 header.resourceID = resourceID;
60 header.operationLocatorLength = opLocatorLength;
61 header.requestPayloadLength = requestPayloadLength;
62
63 std::vector<uint8_t> command(sizeof(header));
64 memcpy(command.data(), &header, sizeof(header));
65 command.insert(command.end(), payloadData.begin(), payloadData.end());
66 return command;
67 }
68
69 // Helper to create MultipartReceiveResHeader and its command data
70 std::vector<uint8_t> createMultiPartRespCmd(
71 uint8_t transferFlag, uint32_t nextDataTransferHandleAsResourceId,
72 uint16_t dataLength, const std::vector<uint8_t>& payloadData,
73 const std::optional<uint32_t>& checksum = std::nullopt)
74 {
75 MultipartReceiveResHeader header{};
76 header.transferFlag = transferFlag;
77 header.nextDataTransferHandle = nextDataTransferHandleAsResourceId;
78 header.dataLengthBytes = dataLength;
79
80 std::vector<uint8_t> command(sizeof(header));
81 memcpy(command.data(), &header, sizeof(header));
82 command.insert(command.end(), payloadData.begin(), payloadData.end());
83
84 if (checksum)
85 {
86 uint32_t csVal = *checksum;
87 command.push_back(static_cast<uint8_t>(csVal & 0xFF));
88 command.push_back(static_cast<uint8_t>((csVal >> 8) & 0xFF));
89 command.push_back(static_cast<uint8_t>((csVal >> 16) & 0xFF));
90 command.push_back(static_cast<uint8_t>((csVal >> 24) & 0xFF));
91 }
92
93 return command;
94 }
95
96 // To be used by EXPECT_CALL
97 MockExternalStorerInterface* mockExStorer;
98};
99
100TEST_F(RdeCommandHandlerTest, DecodeRdeCommand_InvalidType)
101{
102 std::vector<uint8_t> cmdData = {0x01, 0x02};
103 auto status =
104 handler->decodeRdeCommand(cmdData, static_cast<RdeCommandType>(0xFF));
105 EXPECT_EQ(status, RdeDecodeStatus::RdeInvalidCommand);
106}
107
108TEST_F(RdeCommandHandlerTest, GetDictionaryCount_Initial)
109{
110 EXPECT_EQ(handler->getDictionaryCount(), 0);
111}
112
113TEST_F(RdeCommandHandlerTest, OperationInitRequest_NoPayload)
114{
115 auto cmd = createOpInitReqCmd(
116 false, // containsRequestPayload
117 static_cast<uint8_t>(RdeOperationInitType::RdeOpInitOperationUpdate), 0,
118 1, 0, 0);
119 auto status =
120 handler->decodeRdeCommand(cmd, RdeCommandType::RdeOperationInitRequest);
121 EXPECT_EQ(status, RdeDecodeStatus::RdeOk);
122}
123
124TEST_F(RdeCommandHandlerTest, OperationInitRequest_UnsupportedOperationType)
125{
126 auto cmd = createOpInitReqCmd(true, 0xFE, 0, 1, 0, 5, {1, 2, 3, 4, 5});
127 auto status =
128 handler->decodeRdeCommand(cmd, RdeCommandType::RdeOperationInitRequest);
129 EXPECT_EQ(status, RdeDecodeStatus::RdeUnsupportedOperation);
130}
131
132TEST_F(RdeCommandHandlerTest, OperationInitRequest_PayloadOverflowNotSupported)
133{
134 auto cmd = createOpInitReqCmd(
135 true,
136 static_cast<uint8_t>(RdeOperationInitType::RdeOpInitOperationUpdate), 1,
137 1, 0, 5, {1, 2, 3, 4, 5}); // sendDataTransferHandle != 0
138 auto status =
139 handler->decodeRdeCommand(cmd, RdeCommandType::RdeOperationInitRequest);
140 EXPECT_EQ(status, RdeDecodeStatus::RdePayloadOverflow);
141}
142
143TEST_F(RdeCommandHandlerTest, OperationInitRequest_SchemaDictionaryNotFound)
144{
145 std::vector<uint8_t> locatorAndPayload = {0x00}; // Minimal locator
146 auto cmd = createOpInitReqCmd(
147 true,
148 static_cast<uint8_t>(RdeOperationInitType::RdeOpInitOperationUpdate), 0,
149 123, 1, 0, locatorAndPayload); // resourceID 123, opLocatorLength=1,
150 // payloadLength=0
151 auto status =
152 handler->decodeRdeCommand(cmd, RdeCommandType::RdeOperationInitRequest);
153 EXPECT_EQ(status, RdeDecodeStatus::RdeNoDictionary);
154}
155
156TEST_F(RdeCommandHandlerTest, OperationInitRequest_AnnotationDictionaryNotFound)
157{
158 uint32_t schemaResourceId = 1;
159 std::vector<uint8_t> schemaDictData = {'s', 'c', 'h', 'e', 'm', 'a'};
160 uint32_t schemaChecksum = 0xb88e4152; // CRC32("schema")
161 auto cmdSchema = createMultiPartRespCmd(
162 static_cast<uint8_t>(
163 RdeMultiReceiveTransferFlag::RdeMRecFlagStartAndEnd),
164 schemaResourceId, schemaDictData.size(), schemaDictData,
165 schemaChecksum);
166 ASSERT_EQ(handler->decodeRdeCommand(
167 cmdSchema, RdeCommandType::RdeMultiPartReceiveResponse),
168 RdeDecodeStatus::RdeStopFlagReceived);
169
170 std::vector<uint8_t> locatorAndPayload = {0x00};
171 auto cmdOpInit = createOpInitReqCmd(
172 true,
173 static_cast<uint8_t>(RdeOperationInitType::RdeOpInitOperationUpdate), 0,
174 schemaResourceId, 1, 0, locatorAndPayload);
175 auto status = handler->decodeRdeCommand(
176 cmdOpInit, RdeCommandType::RdeOperationInitRequest);
177 EXPECT_EQ(status, RdeDecodeStatus::RdeNoDictionary);
178}
179
180TEST_F(RdeCommandHandlerTest, OperationInitRequest_BejDecodingError)
181{
182 // Add dummy schema dictionary
183 uint32_t schemaResourceId = 1;
184 std::vector<uint8_t> schemaDictData = {'s', 'c', 'h', 'e', 'm', 'a'};
185 uint32_t schemaChecksum = 0xb88e4152; // CRC32("schema")
186 auto cmdSchema = createMultiPartRespCmd(
187 static_cast<uint8_t>(
188 RdeMultiReceiveTransferFlag::RdeMRecFlagStartAndEnd),
189 schemaResourceId, schemaDictData.size(), schemaDictData,
190 schemaChecksum);
191 ASSERT_EQ(handler->decodeRdeCommand(
192 cmdSchema, RdeCommandType::RdeMultiPartReceiveResponse),
193 RdeDecodeStatus::RdeStopFlagReceived);
194
195 // Add dummy annotation dictionary
196 uint32_t annotationResourceId =
197 0; // DictionaryManager::annotationResourceId
198 std::vector<uint8_t> annotationDictData = {'a', 'n', 'n', 'o'};
199 uint32_t annotationChecksum = 0xc6e493b0; // CRC32("anno")
200 auto cmdAnnotation = createMultiPartRespCmd(
201 static_cast<uint8_t>(
202 RdeMultiReceiveTransferFlag::RdeMRecFlagStartAndEnd),
203 annotationResourceId, annotationDictData.size(), annotationDictData,
204 annotationChecksum);
205 ASSERT_EQ(handler->decodeRdeCommand(
206 cmdAnnotation, RdeCommandType::RdeMultiPartReceiveResponse),
207 RdeDecodeStatus::RdeStopFlagReceived);
208
209 std::vector<uint8_t> locator = {0x00};
210 std::vector<uint8_t> bejPayload = {0x01, 0x02}; // Dummy BEJ payload
211 std::vector<uint8_t> opInitFullPayload = locator;
212 opInitFullPayload.insert(opInitFullPayload.end(), bejPayload.begin(),
213 bejPayload.end());
214
215 auto cmdOpInit = createOpInitReqCmd(
216 true,
217 static_cast<uint8_t>(RdeOperationInitType::RdeOpInitOperationUpdate), 0,
218 schemaResourceId, locator.size(), bejPayload.size(), opInitFullPayload);
219
220 // Expect BEJ decoding to fail with invalid dictionaries
221 EXPECT_CALL(*mockExStorer, publishJson(_)).Times(0);
222 auto status = handler->decodeRdeCommand(
223 cmdOpInit, RdeCommandType::RdeOperationInitRequest);
224 EXPECT_EQ(status, RdeDecodeStatus::RdeBejDecodingError);
225}
226
227TEST_F(RdeCommandHandlerTest, OperationInitRequest_ExternalStorerPublishFails)
228{
229 // This test requires BejDecoder to succeed. Since we can't easily mock
230 // BejDecoder or provide universally valid simple BEJ dicts/payloads that
231 // guarantee success for the internal BejDecoder, this specific path is hard
232 // to test in isolation. We would need a known schema, annotation, and
233 // payload that successfully decodes.
234 GTEST_SKIP()
235 << "Skipping due to complexity of ensuring BEJ decode success without mock or valid complex BEJ data.";
236}
237
238TEST_F(RdeCommandHandlerTest, MultiPartReceiveResp_CmdTooSmallForHeader)
239{
240 std::vector<uint8_t> cmdData = {0x01};
241 auto status = handler->decodeRdeCommand(
242 cmdData, RdeCommandType::RdeMultiPartReceiveResponse);
243 EXPECT_EQ(status, RdeDecodeStatus::RdeInvalidCommand);
244}
245
246TEST_F(RdeCommandHandlerTest,
247 MultiPartReceiveResp_CmdTooSmallForDeclaredPayload)
248{
249 MultipartReceiveResHeader header{};
250 header.transferFlag =
251 static_cast<uint8_t>(RdeMultiReceiveTransferFlag::RdeMRecFlagStart);
252 header.nextDataTransferHandle = 1;
253 header.dataLengthBytes = 10; // Expects 10 bytes
254
255 std::vector<uint8_t> cmdData(sizeof(header));
256 memcpy(cmdData.data(), &header, sizeof(header));
257 cmdData.push_back(0xAA); // Only 1 byte of payload provided
258
259 auto status = handler->decodeRdeCommand(
260 cmdData, RdeCommandType::RdeMultiPartReceiveResponse);
261 EXPECT_EQ(status, RdeDecodeStatus::RdeInvalidCommand);
262}
263
264TEST_F(RdeCommandHandlerTest, MultiPartReceiveResp_InvalidTransferFlag)
265{
266 std::vector<uint8_t> payload = {'d', 'a', 't', 'a'};
267 auto cmd = createMultiPartRespCmd(0xFF, 1, payload.size(),
268 payload); // Invalid flag
269 auto status = handler->decodeRdeCommand(
270 cmd, RdeCommandType::RdeMultiPartReceiveResponse);
271 EXPECT_EQ(status, RdeDecodeStatus::RdeInvalidCommand);
272}
273
274TEST_F(RdeCommandHandlerTest, MultiPartReceiveResp_FlagStart)
275{
276 uint32_t resourceId = 1;
277 std::vector<uint8_t> dataPayload = {'s', 't', 'a', 'r', 't'};
278 auto cmd = createMultiPartRespCmd(
279 static_cast<uint8_t>(RdeMultiReceiveTransferFlag::RdeMRecFlagStart),
280 resourceId, dataPayload.size(), dataPayload);
281 auto status = handler->decodeRdeCommand(
282 cmd, RdeCommandType::RdeMultiPartReceiveResponse);
283 EXPECT_EQ(status, RdeDecodeStatus::RdeOk);
284 EXPECT_EQ(handler->getDictionaryCount(), 0); // Not yet complete
285}
286
287TEST_F(RdeCommandHandlerTest, MultiPartReceiveResp_FlagMiddle_InvalidOrder)
288{
289 uint32_t resourceId = 1;
290 std::vector<uint8_t> dataPayload = {'m', 'i', 'd', 'd', 'l', 'e'};
291 auto cmd = createMultiPartRespCmd(
292 static_cast<uint8_t>(RdeMultiReceiveTransferFlag::RdeMRecFlagMiddle),
293 resourceId, dataPayload.size(), dataPayload);
294 auto status = handler->decodeRdeCommand(
295 cmd, RdeCommandType::RdeMultiPartReceiveResponse);
296 EXPECT_EQ(status, RdeDecodeStatus::RdeInvalidPktOrder);
297}
298
299TEST_F(RdeCommandHandlerTest,
300 MultiPartReceiveResp_FlagMiddle_AfterStart_SameResource)
301{
302 uint32_t resourceId = 1;
303 std::vector<uint8_t> startPayload = {'s', 't', 'a', 'r', 't'};
304 auto cmdStart = createMultiPartRespCmd(
305 static_cast<uint8_t>(RdeMultiReceiveTransferFlag::RdeMRecFlagStart),
306 resourceId, startPayload.size(), startPayload);
307 ASSERT_EQ(handler->decodeRdeCommand(
308 cmdStart, RdeCommandType::RdeMultiPartReceiveResponse),
309 RdeDecodeStatus::RdeOk);
310
311 std::vector<uint8_t> middlePayload = {'m', 'i', 'd', 'd', 'l', 'e'};
312 auto cmdMiddle = createMultiPartRespCmd(
313 static_cast<uint8_t>(RdeMultiReceiveTransferFlag::RdeMRecFlagMiddle),
314 resourceId, middlePayload.size(), middlePayload);
315 auto status = handler->decodeRdeCommand(
316 cmdMiddle, RdeCommandType::RdeMultiPartReceiveResponse);
317 EXPECT_EQ(status, RdeDecodeStatus::RdeOk);
318 EXPECT_EQ(handler->getDictionaryCount(), 0);
319}
320
321TEST_F(RdeCommandHandlerTest,
322 MultiPartReceiveResp_FlagMiddle_AfterStart_NewResource)
323{
324 // Tests current behavior: if Middle flag comes for a new resource,
325 // previous resource is marked complete, new one is started. CRC continues.
326 uint32_t resourceId1 = 1;
327 std::vector<uint8_t> startPayload1 = {'r', '1', 's'};
328 auto cmdStart1 = createMultiPartRespCmd(
329 static_cast<uint8_t>(RdeMultiReceiveTransferFlag::RdeMRecFlagStart),
330 resourceId1, startPayload1.size(), startPayload1);
331 ASSERT_EQ(handler->decodeRdeCommand(
332 cmdStart1, RdeCommandType::RdeMultiPartReceiveResponse),
333 RdeDecodeStatus::RdeOk);
334
335 uint32_t resourceId2 = 2;
336 std::vector<uint8_t> middlePayload2 = {'r', '2', 'm'};
337 auto cmdMiddle2 = createMultiPartRespCmd(
338 static_cast<uint8_t>(RdeMultiReceiveTransferFlag::RdeMRecFlagMiddle),
339 resourceId2, middlePayload2.size(), middlePayload2);
340 auto status = handler->decodeRdeCommand(
341 cmdMiddle2, RdeCommandType::RdeMultiPartReceiveResponse);
342 EXPECT_EQ(status, RdeDecodeStatus::RdeOk);
343 EXPECT_EQ(handler->getDictionaryCount(), 1); // Resource 1 completed
344}
345
346TEST_F(RdeCommandHandlerTest, MultiPartReceiveResp_FlagEnd_InvalidOrder)
347{
348 uint32_t resourceId = 1;
349 std::vector<uint8_t> dataPayload = {'e', 'n', 'd'};
350 uint32_t checksum = 0xfc33b1; // CRC32("end")
351 auto cmd = createMultiPartRespCmd(
352 static_cast<uint8_t>(RdeMultiReceiveTransferFlag::RdeMRecFlagEnd),
353 resourceId, dataPayload.size(), dataPayload, checksum);
354 auto status = handler->decodeRdeCommand(
355 cmd, RdeCommandType::RdeMultiPartReceiveResponse);
356 EXPECT_EQ(status, RdeDecodeStatus::RdeInvalidPktOrder);
357}
358
359TEST_F(RdeCommandHandlerTest,
360 MultiPartReceiveResp_FlagEnd_AfterStart_SameResource_ValidChecksum)
361{
362 uint32_t resourceId = 1;
363 std::vector<uint8_t> startPayload = {'s', 't', 'a', 'r', 't'};
364 auto cmdStart = createMultiPartRespCmd(
365 static_cast<uint8_t>(RdeMultiReceiveTransferFlag::RdeMRecFlagStart),
366 resourceId, startPayload.size(), startPayload);
367 ASSERT_EQ(handler->decodeRdeCommand(
368 cmdStart, RdeCommandType::RdeMultiPartReceiveResponse),
369 RdeDecodeStatus::RdeOk);
370
371 std::vector<uint8_t> endPayload = {'e', 'n', 'd'};
372 uint32_t checksum = 0x4800f1a; // CRC32("startend")
373 auto cmdEnd = createMultiPartRespCmd(
374 static_cast<uint8_t>(RdeMultiReceiveTransferFlag::RdeMRecFlagEnd),
375 resourceId, endPayload.size(), endPayload, checksum);
376 auto status = handler->decodeRdeCommand(
377 cmdEnd, RdeCommandType::RdeMultiPartReceiveResponse);
378 EXPECT_EQ(status, RdeDecodeStatus::RdeStopFlagReceived);
379 EXPECT_EQ(handler->getDictionaryCount(), 1);
380}
381
382TEST_F(RdeCommandHandlerTest,
383 MultiPartReceiveResp_FlagEnd_AfterStart_SameResource_InvalidChecksum)
384{
385 uint32_t resourceId = 1;
386 std::vector<uint8_t> startPayload = {'s', 't', 'a', 'r', 't'};
387 auto cmdStart = createMultiPartRespCmd(
388 static_cast<uint8_t>(RdeMultiReceiveTransferFlag::RdeMRecFlagStart),
389 resourceId, startPayload.size(), startPayload);
390 ASSERT_EQ(handler->decodeRdeCommand(
391 cmdStart, RdeCommandType::RdeMultiPartReceiveResponse),
392 RdeDecodeStatus::RdeOk);
393
394 std::vector<uint8_t> endPayload = {'e', 'n', 'd'};
395 uint32_t invalidChecksum = 0x12345678; // Invalid checksum
396 auto cmdEnd = createMultiPartRespCmd(
397 static_cast<uint8_t>(RdeMultiReceiveTransferFlag::RdeMRecFlagEnd),
398 resourceId, endPayload.size(), endPayload, invalidChecksum);
399 auto status = handler->decodeRdeCommand(
400 cmdEnd, RdeCommandType::RdeMultiPartReceiveResponse);
401 EXPECT_EQ(status, RdeDecodeStatus::RdeInvalidChecksum);
402 EXPECT_EQ(handler->getDictionaryCount(), 0); // Dictionaries invalidated
403}
404
405TEST_F(RdeCommandHandlerTest,
406 MultiPartReceiveResp_FlagEnd_AfterStart_NewResource_UsesPrevCrcState)
407{
408 // This test verifies that if an End flag for a new resource follows a Start
409 // flag for a different resource, the CRC calculation for the new resource's
410 // data incorrectly continues from the previous resource's CRC state.
411 uint32_t resourceId1 = 1;
412 std::vector<uint8_t> startPayload1 = {'r', '1', 's'}; // CRC for "r1s"
413 auto cmdStart1 = createMultiPartRespCmd(
414 static_cast<uint8_t>(RdeMultiReceiveTransferFlag::RdeMRecFlagStart),
415 resourceId1, startPayload1.size(), startPayload1);
416 ASSERT_EQ(handler->decodeRdeCommand(
417 cmdStart1, RdeCommandType::RdeMultiPartReceiveResponse),
418 RdeDecodeStatus::RdeOk);
419
420 uint32_t resourceId2 = 2;
421 std::vector<uint8_t> endPayload2 = {'r', '2', 'e'};
422 // Checksum for "r2e" ALONE is 0x789ca48a.
423 // If CRC continued from "r1s", this checksum will be wrong.
424 uint32_t checksumForR2eAlone = 0x789ca48a;
425 auto cmdEnd2 = createMultiPartRespCmd(
426 static_cast<uint8_t>(RdeMultiReceiveTransferFlag::RdeMRecFlagEnd),
427 resourceId2, endPayload2.size(), endPayload2, checksumForR2eAlone);
428
429 auto status = handler->decodeRdeCommand(
430 cmdEnd2, RdeCommandType::RdeMultiPartReceiveResponse);
431 // Expect InvalidChecksum because internal CRC is for "r1s" + "r2e"
432 EXPECT_EQ(status, RdeDecodeStatus::RdeInvalidChecksum);
433 EXPECT_EQ(handler->getDictionaryCount(), 0); // Dictionaries invalidated
434}
435
436TEST_F(RdeCommandHandlerTest,
437 MultiPartReceiveResp_FlagStartAndEnd_ValidChecksum)
438{
439 uint32_t resourceId = 1;
440 std::vector<uint8_t> dataPayload = {'c', 'o', 'm', 'p', 'l', 'e', 't', 'e'};
441 uint32_t checksum = 0x4267d023; // CRC32("complete")
442 auto cmd = createMultiPartRespCmd(
443 static_cast<uint8_t>(
444 RdeMultiReceiveTransferFlag::RdeMRecFlagStartAndEnd),
445 resourceId, dataPayload.size(), dataPayload, checksum);
446 auto status = handler->decodeRdeCommand(
447 cmd, RdeCommandType::RdeMultiPartReceiveResponse);
448 EXPECT_EQ(status, RdeDecodeStatus::RdeStopFlagReceived);
449 EXPECT_EQ(handler->getDictionaryCount(), 1);
450}
451
452TEST_F(RdeCommandHandlerTest,
453 MultiPartReceiveResp_FlagStartAndEnd_InvalidChecksum)
454{
455 uint32_t resourceId = 1;
456 std::vector<uint8_t> dataPayload = {'c', 'o', 'm', 'p', 'l', 'e', 't', 'e'};
457 uint32_t invalidChecksum = 0x12345678; // Invalid checksum
458 auto cmd = createMultiPartRespCmd(
459 static_cast<uint8_t>(
460 RdeMultiReceiveTransferFlag::RdeMRecFlagStartAndEnd),
461 resourceId, dataPayload.size(), dataPayload, invalidChecksum);
462 auto status = handler->decodeRdeCommand(
463 cmd, RdeCommandType::RdeMultiPartReceiveResponse);
464 EXPECT_EQ(status, RdeDecodeStatus::RdeInvalidChecksum);
465 EXPECT_EQ(handler->getDictionaryCount(), 0);
466}
467
468TEST_F(RdeCommandHandlerTest,
469 MultiPartReceiveResp_Sequence_StartMiddleEnd_Valid)
470{
471 uint32_t resourceId = 42;
472
473 std::vector<uint8_t> startPayload = {'p', 'a', 'r', 't', '1'};
474 auto cmdStart = createMultiPartRespCmd(
475 static_cast<uint8_t>(RdeMultiReceiveTransferFlag::RdeMRecFlagStart),
476 resourceId, startPayload.size(), startPayload);
477 ASSERT_EQ(handler->decodeRdeCommand(
478 cmdStart, RdeCommandType::RdeMultiPartReceiveResponse),
479 RdeDecodeStatus::RdeOk);
480
481 std::vector<uint8_t> middlePayload = {'p', 'a', 'r', 't', '2'};
482 auto cmdMiddle = createMultiPartRespCmd(
483 static_cast<uint8_t>(RdeMultiReceiveTransferFlag::RdeMRecFlagMiddle),
484 resourceId, middlePayload.size(), middlePayload);
485 ASSERT_EQ(handler->decodeRdeCommand(
486 cmdMiddle, RdeCommandType::RdeMultiPartReceiveResponse),
487 RdeDecodeStatus::RdeOk);
488
489 std::vector<uint8_t> endPayload = {'p', 'a', 'r', 't', '3'};
490 uint32_t checksum = 0xf5295f3; // CRC32("part1part2part3")
491 auto cmdEnd = createMultiPartRespCmd(
492 static_cast<uint8_t>(RdeMultiReceiveTransferFlag::RdeMRecFlagEnd),
493 resourceId, endPayload.size(), endPayload, checksum);
494 auto status = handler->decodeRdeCommand(
495 cmdEnd, RdeCommandType::RdeMultiPartReceiveResponse);
496 EXPECT_EQ(status, RdeDecodeStatus::RdeStopFlagReceived);
497 EXPECT_EQ(handler->getDictionaryCount(), 1);
498}
499
500TEST_F(RdeCommandHandlerTest,
501 MultiPartReceiveResp_MultipleDictionaries_ValidSequence)
502{
503 // Dictionary 1: StartAndEnd
504 uint32_t resourceId1 = 1;
505 std::vector<uint8_t> payload1 = {'d', 'i', 'c', 't', '1'};
506 uint32_t checksum1 = 0xbca257a8; // CRC32("dict1")
507 auto cmd1 = createMultiPartRespCmd(
508 static_cast<uint8_t>(
509 RdeMultiReceiveTransferFlag::RdeMRecFlagStartAndEnd),
510 resourceId1, payload1.size(), payload1, checksum1);
511 ASSERT_EQ(handler->decodeRdeCommand(
512 cmd1, RdeCommandType::RdeMultiPartReceiveResponse),
513 RdeDecodeStatus::RdeStopFlagReceived);
514 ASSERT_EQ(handler->getDictionaryCount(), 1);
515
516 // Dictionary 2: Start, Middle, End
517 uint32_t resourceId2 = 2;
518 std::vector<uint8_t> startPayload2 = {'d', '2', '_'};
519 auto cmdStart2 = createMultiPartRespCmd(
520 static_cast<uint8_t>(RdeMultiReceiveTransferFlag::RdeMRecFlagStart),
521 resourceId2, startPayload2.size(), startPayload2);
522 ASSERT_EQ(handler->decodeRdeCommand(
523 cmdStart2, RdeCommandType::RdeMultiPartReceiveResponse),
524 RdeDecodeStatus::RdeOk);
525 ASSERT_EQ(handler->getDictionaryCount(),
526 1); // Dict1 still valid, Dict2 not yet
527
528 std::vector<uint8_t> middlePayload2 = {'m', 'i', 'd'};
529 auto cmdMiddle2 = createMultiPartRespCmd(
530 static_cast<uint8_t>(RdeMultiReceiveTransferFlag::RdeMRecFlagMiddle),
531 resourceId2, middlePayload2.size(), middlePayload2);
532 ASSERT_EQ(handler->decodeRdeCommand(
533 cmdMiddle2, RdeCommandType::RdeMultiPartReceiveResponse),
534 RdeDecodeStatus::RdeOk);
535
536 std::vector<uint8_t> endPayload2 = {'e', 'n', 'd'};
537 uint32_t checksum2 = 0x9e428a17; // CRC32("d2_midend")
538 auto cmdEnd2 = createMultiPartRespCmd(
539 static_cast<uint8_t>(RdeMultiReceiveTransferFlag::RdeMRecFlagEnd),
540 resourceId2, endPayload2.size(), endPayload2, checksum2);
541 ASSERT_EQ(handler->decodeRdeCommand(
542 cmdEnd2, RdeCommandType::RdeMultiPartReceiveResponse),
543 RdeDecodeStatus::RdeStopFlagReceived);
544 ASSERT_EQ(handler->getDictionaryCount(),
545 2); // Both dictionaries should now be valid
546}
547
kasunathbac958d2022-06-07 18:15:24 -0700548/**
549 * @brief Dummy values for annotation dictionary. We do not need the annotation
550 * dictionary. So this contains a dictionary with some dummy values. But the RDE
551 * header is correct.
552 */
553constexpr std::array<uint8_t, 38> mRcvDummyAnnotation{
554 {0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
555 0x0, 0x0, 0xc, 0x0, 0x0, 0xf0, 0xf0, 0xf1, 0x17, 0x1,
556 0x0, 0x0, 0x0, 0x0, 0x0, 0x16, 0x0, 0x5, 0x0, 0xc,
557 0x84, 0x0, 0x14, 0x0, 0x30, 0xa8, 0xc3, 0x3c}};
558
559constexpr std::array<uint8_t, 38> mRcvDummyInvalidChecksum{
560 {0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
561 0x0, 0x0, 0xc, 0x0, 0x0, 0xf0, 0xf0, 0xf1, 0x17, 0x1,
562 0x0, 0x0, 0x0, 0x0, 0x0, 0x16, 0x0, 0x5, 0x0, 0xc,
563 0x84, 0x0, 0x14, 0x0, 0x17, 0x86, 0x00, 0x00}};
564
565/**
566 * @brief MultipartReceive command with START_AND_END flag set.
567 */
568constexpr std::array<uint8_t, 293> mRcvInput0StartAndEnd{
569 {0x00, 0x03, 0x02, 0x00, 0x00, 0x00, 0x17, 0x01, 0x00, 0x00, 0x0, 0x0,
570 0xc, 0x0, 0x0, 0xf0, 0xf0, 0xf1, 0x17, 0x1, 0x0, 0x0, 0x0, 0x0,
571 0x0, 0x16, 0x0, 0x5, 0x0, 0xc, 0x84, 0x0, 0x14, 0x0, 0x0, 0x48,
572 0x0, 0x1, 0x0, 0x13, 0x90, 0x0, 0x56, 0x1, 0x0, 0x0, 0x0, 0x0,
573 0x0, 0x3, 0xa3, 0x0, 0x74, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x16,
574 0xa6, 0x0, 0x34, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x16, 0xbc, 0x0,
575 0x64, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x13, 0xd2, 0x0, 0x0, 0x0,
576 0x0, 0x52, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x74, 0x0, 0x0, 0x0,
577 0x0, 0x0, 0x0, 0xf, 0xe5, 0x0, 0x46, 0x1, 0x0, 0x66, 0x0, 0x3,
578 0x0, 0xb, 0xf4, 0x0, 0x50, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9,
579 0xff, 0x0, 0x50, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0x8, 0x1,
580 0x50, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xf, 0x1, 0x44, 0x75,
581 0x6d, 0x6d, 0x79, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x0, 0x43, 0x68,
582 0x69, 0x6c, 0x64, 0x41, 0x72, 0x72, 0x61, 0x79, 0x50, 0x72, 0x6f, 0x70,
583 0x65, 0x72, 0x74, 0x79, 0x0, 0x49, 0x64, 0x0, 0x53, 0x61, 0x6d, 0x70,
584 0x6c, 0x65, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x50, 0x72, 0x6f,
585 0x70, 0x65, 0x72, 0x74, 0x79, 0x0, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65,
586 0x49, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x70, 0x65,
587 0x72, 0x74, 0x79, 0x0, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x52, 0x65,
588 0x61, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x0, 0x41,
589 0x6e, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x42, 0x6f, 0x6f, 0x6c, 0x65, 0x61,
590 0x6e, 0x0, 0x4c, 0x69, 0x6e, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
591 0x0, 0x4c, 0x69, 0x6e, 0x6b, 0x44, 0x6f, 0x77, 0x6e, 0x0, 0x4c, 0x69,
592 0x6e, 0x6b, 0x55, 0x70, 0x0, 0x4e, 0x6f, 0x4c, 0x69, 0x6e, 0x6b, 0x0,
593 0x0, 0x8c, 0x87, 0xed, 0x74}};
594
595/**
596 * @brief MultipartReceive command with START flag set.
597 */
598constexpr std::array<uint8_t, 166> mRcvInput1Start{
599 {0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x0, 0x0,
600 0xc, 0x0, 0x0, 0xf0, 0xf0, 0xf1, 0x17, 0x1, 0x0, 0x0, 0x0, 0x0,
601 0x0, 0x16, 0x0, 0x5, 0x0, 0xc, 0x84, 0x0, 0x14, 0x0, 0x0, 0x48,
602 0x0, 0x1, 0x0, 0x13, 0x90, 0x0, 0x56, 0x1, 0x0, 0x0, 0x0, 0x0,
603 0x0, 0x3, 0xa3, 0x0, 0x74, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x16,
604 0xa6, 0x0, 0x34, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x16, 0xbc, 0x0,
605 0x64, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x13, 0xd2, 0x0, 0x0, 0x0,
606 0x0, 0x52, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x74, 0x0, 0x0, 0x0,
607 0x0, 0x0, 0x0, 0xf, 0xe5, 0x0, 0x46, 0x1, 0x0, 0x66, 0x0, 0x3,
608 0x0, 0xb, 0xf4, 0x0, 0x50, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9,
609 0xff, 0x0, 0x50, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0x8, 0x1,
610 0x50, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xf, 0x1, 0x44, 0x75,
611 0x6d, 0x6d, 0x79, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x0, 0x43, 0x68,
612 0x69, 0x6c, 0x64, 0x41, 0x72, 0x72, 0x61, 0x79, 0x50, 0x72}};
613
614/**
615 * @brief MultipartReceive command with END flag set.
616 */
617constexpr std::array<uint8_t, 137> mRcvInput1End{
618 {0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x6f, 0x70,
619 0x65, 0x72, 0x74, 0x79, 0x0, 0x49, 0x64, 0x0, 0x53, 0x61, 0x6d, 0x70,
620 0x6c, 0x65, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x50, 0x72, 0x6f,
621 0x70, 0x65, 0x72, 0x74, 0x79, 0x0, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65,
622 0x49, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x70, 0x65,
623 0x72, 0x74, 0x79, 0x0, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x52, 0x65,
624 0x61, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x0, 0x41,
625 0x6e, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x42, 0x6f, 0x6f, 0x6c, 0x65, 0x61,
626 0x6e, 0x0, 0x4c, 0x69, 0x6e, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
627 0x0, 0x4c, 0x69, 0x6e, 0x6b, 0x44, 0x6f, 0x77, 0x6e, 0x0, 0x4c, 0x69,
628 0x6e, 0x6b, 0x55, 0x70, 0x0, 0x4e, 0x6f, 0x4c, 0x69, 0x6e, 0x6b, 0x0,
629 0x0, 0x8c, 0x87, 0xed, 0x74}};
630
631/**
632 * @brief MultipartReceive command with START flag set.
633 */
634constexpr std::array<uint8_t, 106> mRcvInput2Start{
635 {0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x60, 0x0, 0x00, 0x00, 0x0, 0x0,
636 0xc, 0x0, 0x0, 0xf0, 0xf0, 0xf1, 0x17, 0x1, 0x0, 0x0, 0x0, 0x0,
637 0x0, 0x16, 0x0, 0x5, 0x0, 0xc, 0x84, 0x0, 0x14, 0x0, 0x0, 0x48,
638 0x0, 0x1, 0x0, 0x13, 0x90, 0x0, 0x56, 0x1, 0x0, 0x0, 0x0, 0x0,
639 0x0, 0x3, 0xa3, 0x0, 0x74, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x16,
640 0xa6, 0x0, 0x34, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x16, 0xbc, 0x0,
641 0x64, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x13, 0xd2, 0x0, 0x0, 0x0,
642 0x0, 0x52, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x74, 0x0, 0x0, 0x0,
643 0x0, 0x0, 0x0, 0xf, 0xe5, 0x0, 0x46, 0x1, 0x0, 0x66}};
644
645/**
646 * @brief MultipartReceive command with MIDDLE flag set.
647 */
648constexpr std::array<uint8_t, 106> mRcvInput2Mid{
649 {0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x60, 0x0, 0x00, 0x00, 0x0, 0x3,
650 0x0, 0xb, 0xf4, 0x0, 0x50, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9,
651 0xff, 0x0, 0x50, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0x8, 0x1,
652 0x50, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xf, 0x1, 0x44, 0x75,
653 0x6d, 0x6d, 0x79, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x0, 0x43, 0x68,
654 0x69, 0x6c, 0x64, 0x41, 0x72, 0x72, 0x61, 0x79, 0x50, 0x72, 0x6f, 0x70,
655 0x65, 0x72, 0x74, 0x79, 0x0, 0x49, 0x64, 0x0, 0x53, 0x61, 0x6d, 0x70,
656 0x6c, 0x65, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x50, 0x72, 0x6f,
657 0x70, 0x65, 0x72, 0x74, 0x79, 0x0, 0x53, 0x61, 0x6d, 0x70}};
658
659/**
660 * @brief MultipartReceive command with END flag set.
661 */
662constexpr std::array<uint8_t, 101> mRcvInput2End{
663 {0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x57, 0x0, 0x00, 0x00, 0x6c, 0x65,
664 0x49, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x70, 0x65,
665 0x72, 0x74, 0x79, 0x0, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x52, 0x65,
666 0x61, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x0, 0x41,
667 0x6e, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x42, 0x6f, 0x6f, 0x6c, 0x65, 0x61,
668 0x6e, 0x0, 0x4c, 0x69, 0x6e, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
669 0x0, 0x4c, 0x69, 0x6e, 0x6b, 0x44, 0x6f, 0x77, 0x6e, 0x0, 0x4c, 0x69,
670 0x6e, 0x6b, 0x55, 0x70, 0x0, 0x4e, 0x6f, 0x4c, 0x69, 0x6e, 0x6b, 0x0,
671 0x0, 0x8c, 0x87, 0xed, 0x74}};
672
673/**
674 * @brief RDEOperationInit command with encoded json/dummysimple.json as the
675 * payload.
676 */
677constexpr std::array<uint8_t, 113> mInitOp{
678 {0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00,
679 0x00, 0x60, 0x00, 0x00, 0x00, 0x0, 0xf0, 0xf0, 0xf1, 0x0, 0x0, 0x0,
680 0x1, 0x0, 0x0, 0x1, 0x54, 0x1, 0x5, 0x1, 0x2, 0x50, 0x1, 0x9,
681 0x44, 0x75, 0x6d, 0x6d, 0x79, 0x20, 0x49, 0x44, 0x0, 0x1, 0x6, 0x20,
682 0x1, 0x0, 0x1, 0x8, 0x60, 0x1, 0xb, 0x1, 0x2, 0x38, 0xea, 0x1,
683 0x0, 0x2, 0xa3, 0x23, 0x1, 0x0, 0x1, 0x4, 0x70, 0x1, 0x1, 0x0,
684 0x1, 0x0, 0x10, 0x1, 0x24, 0x1, 0x2, 0x1, 0x0, 0x0, 0x1, 0xf,
685 0x1, 0x2, 0x1, 0x0, 0x70, 0x1, 0x1, 0x1, 0x1, 0x2, 0x40, 0x1,
686 0x2, 0x1, 0x2, 0x1, 0x2, 0x0, 0x1, 0x9, 0x1, 0x1, 0x1, 0x2,
687 0x40, 0x1, 0x2, 0x1, 0x2}};
688
689class MockExternalStorer : public ExternalStorerInterface
690{
691 public:
692 MOCK_METHOD(bool, publishJson, (std::string_view jsonStr), (override));
693};
694
695class RdeHandlerTest : public ::testing::Test
696{
697 public:
698 RdeHandlerTest() : mockExStorer(std::make_unique<MockExternalStorer>())
699 {
700 mockExStorerPtr = dynamic_cast<MockExternalStorer*>(mockExStorer.get());
701 rdeH = std::make_unique<RdeCommandHandler>(std::move(mockExStorer));
702 }
703
704 protected:
705 std::unique_ptr<ExternalStorerInterface> mockExStorer;
706 std::unique_ptr<RdeCommandHandler> rdeH;
707 MockExternalStorer* mockExStorerPtr;
708 const std::string exJson =
709 R"({"Id":"Dummy ID","SampleIntegerProperty":null,"SampleRealProperty":-5576.9123,"SampleEnabledProperty":false,"ChildArrayProperty":[{"AnotherBoolean":true,"LinkStatus":"NoLink"},{"LinkStatus":"NoLink"}]})";
710};
711
712TEST_F(RdeHandlerTest, DictionaryStartAndEndTest)
713{
714 // Send a payload with START_AND_END flag.
715 EXPECT_THAT(
716 rdeH->decodeRdeCommand(std::span(mRcvInput0StartAndEnd),
717 RdeCommandType::RdeMultiPartReceiveResponse),
718 RdeDecodeStatus::RdeStopFlagReceived);
719 EXPECT_THAT(rdeH->getDictionaryCount(), 1);
720 // Send annotation dictionary.
721 EXPECT_THAT(
722 rdeH->decodeRdeCommand(std::span(mRcvDummyAnnotation),
723 RdeCommandType::RdeMultiPartReceiveResponse),
724 RdeDecodeStatus::RdeStopFlagReceived);
725 EXPECT_THAT(rdeH->getDictionaryCount(), 2);
726
727 // Send the encoded payload.
728 EXPECT_CALL(*mockExStorerPtr, publishJson(exJson)).WillOnce(Return(true));
729 EXPECT_THAT(rdeH->decodeRdeCommand(std::span(mInitOp),
730 RdeCommandType::RdeOperationInitRequest),
731 RdeDecodeStatus::RdeOk);
732}
733
734TEST_F(RdeHandlerTest, DictionaryStartThenEndTest)
735{
736 // Send a payload with START flag.
737 EXPECT_THAT(
738 rdeH->decodeRdeCommand(std::span(mRcvInput1Start),
739 RdeCommandType::RdeMultiPartReceiveResponse),
740 RdeDecodeStatus::RdeOk);
741 // We didn't send END. So dictionary count should be 0.
742 EXPECT_THAT(rdeH->getDictionaryCount(), 0);
743 // Send a payload with END flag.
744 EXPECT_THAT(
745 rdeH->decodeRdeCommand(std::span(mRcvInput1End),
746 RdeCommandType::RdeMultiPartReceiveResponse),
747 RdeDecodeStatus::RdeStopFlagReceived);
748 EXPECT_THAT(rdeH->getDictionaryCount(), 1);
749 // Send annotation dictionary.
750 EXPECT_THAT(
751 rdeH->decodeRdeCommand(std::span(mRcvDummyAnnotation),
752 RdeCommandType::RdeMultiPartReceiveResponse),
753 RdeDecodeStatus::RdeStopFlagReceived);
754 EXPECT_THAT(rdeH->getDictionaryCount(), 2);
755
756 // Send the encoded payload.
757 EXPECT_CALL(*mockExStorerPtr, publishJson(exJson)).WillOnce(Return(true));
758 EXPECT_THAT(rdeH->decodeRdeCommand(std::span(mInitOp),
759 RdeCommandType::RdeOperationInitRequest),
760 RdeDecodeStatus::RdeOk);
761
762 // Sending the START again for same resource ID should decrease the
763 // dictionary count.
764 EXPECT_THAT(
765 rdeH->decodeRdeCommand(std::span(mRcvInput1Start),
766 RdeCommandType::RdeMultiPartReceiveResponse),
767 RdeDecodeStatus::RdeOk);
768 EXPECT_THAT(rdeH->getDictionaryCount(), 1);
769}
770
771TEST_F(RdeHandlerTest, DictionaryStartMidEndTest)
772{
773 // Send a payload with START flag.
774 EXPECT_THAT(
775 rdeH->decodeRdeCommand(std::span(mRcvInput2Start),
776 RdeCommandType::RdeMultiPartReceiveResponse),
777 RdeDecodeStatus::RdeOk);
778 // We didn't send END. So dictionary count should be 0.
779 EXPECT_THAT(rdeH->getDictionaryCount(), 0);
780 // Send a payload with MIDDLE flag.
781 EXPECT_THAT(
782 rdeH->decodeRdeCommand(std::span(mRcvInput2Mid),
783 RdeCommandType::RdeMultiPartReceiveResponse),
784 RdeDecodeStatus::RdeOk);
785 // We didn't send END. So dictionary count should be 0.
786 EXPECT_THAT(rdeH->getDictionaryCount(), 0);
787 // Send a payload with END flag.
788 EXPECT_THAT(
789 rdeH->decodeRdeCommand(std::span(mRcvInput2End),
790 RdeCommandType::RdeMultiPartReceiveResponse),
791 RdeDecodeStatus::RdeStopFlagReceived);
792 EXPECT_THAT(rdeH->getDictionaryCount(), 1);
793
794 // Send annotation dictionary.
795 EXPECT_THAT(
796 rdeH->decodeRdeCommand(std::span(mRcvDummyAnnotation),
797 RdeCommandType::RdeMultiPartReceiveResponse),
798 RdeDecodeStatus::RdeStopFlagReceived);
799 EXPECT_THAT(rdeH->getDictionaryCount(), 2);
800
801 // Send the encoded payload.
802 EXPECT_CALL(*mockExStorerPtr, publishJson(exJson)).WillOnce(Return(true));
803 EXPECT_THAT(rdeH->decodeRdeCommand(std::span(mInitOp),
804 RdeCommandType::RdeOperationInitRequest),
805 RdeDecodeStatus::RdeOk);
806}
807
808TEST_F(RdeHandlerTest, InvalidDictionaryFlowTest)
809{
810 // Send a payload with MIDDLE flag before START and it should fail.
811 EXPECT_THAT(
812 rdeH->decodeRdeCommand(std::span(mRcvInput2Mid),
813 RdeCommandType::RdeMultiPartReceiveResponse),
814 RdeDecodeStatus::RdeInvalidPktOrder);
815 // Send a payload with END flag before START and it should fail.
816 EXPECT_THAT(
817 rdeH->decodeRdeCommand(std::span(mRcvInput2End),
818 RdeCommandType::RdeMultiPartReceiveResponse),
819 RdeDecodeStatus::RdeInvalidPktOrder);
820}
821
822TEST_F(RdeHandlerTest, MissingDictionaryTest)
823{
824 // Try decoding without any dictionaries.
825 EXPECT_THAT(rdeH->decodeRdeCommand(std::span(mInitOp),
826 RdeCommandType::RdeOperationInitRequest),
827 RdeDecodeStatus::RdeNoDictionary);
828
829 // Try decoding just with annotation dictionary.
830 EXPECT_THAT(
831 rdeH->decodeRdeCommand(std::span(mRcvDummyAnnotation),
832 RdeCommandType::RdeMultiPartReceiveResponse),
833 RdeDecodeStatus::RdeStopFlagReceived);
834 EXPECT_THAT(rdeH->decodeRdeCommand(std::span(mInitOp),
835 RdeCommandType::RdeOperationInitRequest),
836 RdeDecodeStatus::RdeNoDictionary);
837}
838
839TEST_F(RdeHandlerTest, InvalidDictionaryChecksumTest)
840{
841 // Send a dictionary with an invalid checksum.
842 EXPECT_THAT(
843 rdeH->decodeRdeCommand(std::span(mRcvDummyInvalidChecksum),
844 RdeCommandType::RdeMultiPartReceiveResponse),
845 RdeDecodeStatus::RdeInvalidChecksum);
846}
847
848} // namespace rde
849} // namespace bios_bmc_smm_error_logger