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