ud3tn/test/unit/test_bundle7Parser.c
Felix Walter 62d563449f test: Remove the Unity wrappers for memory allocation functions
This adds a custom header that does explicitly not include the Unity
wrappers for malloc, free, etc. by defining the guard used by that header
file. This way we can remove the wrappers provided via the linker
altogether.

Signed-off-by: Felix Walter <felix.walter@d3tn.com>
2023-05-15 11:39:29 +02:00

538 lines
14 KiB
C

// SPDX-License-Identifier: BSD-3-Clause OR Apache-2.0
/**
* Unit Test for BPbis parser
*
* Raw CBOR data is loaded from "test_bundle7Data.c".
*/
#include "bundle7/eid.h"
#include "bundle7/parser.h"
#include "bundle7/reports.h"
#include "bundle7/hopcount.h"
#include "bundle7/bundle_age.h"
#include "ud3tn/bundle.h"
#include "ud3tn/report_manager.h"
#include "testud3tn_unity.h"
#include <stdlib.h>
#include <string.h>
TEST_GROUP(bundle7Parser);
extern uint8_t cbor_simple_bundle[];
extern size_t len_simple_bundle;
static struct bundle *bundle;
static void send_callback(struct bundle *_bundle, void *param)
{
(void)param;
bundle = _bundle;
}
TEST_SETUP(bundle7Parser)
{
bundle = NULL;
}
TEST_TEAR_DOWN(bundle7Parser)
{
if (bundle != NULL) {
bundle_free(bundle);
bundle = NULL;
}
}
TEST(bundle7Parser, eid_parser)
{
char *eid;
const uint8_t sat_1[] = { 0x82, 0x01, 0x64, 0x53, 0x41, 0x54, 0x31 };
const uint8_t ipn[] = { 0x82, 0x02, 0x82, 0x18, 0x2a, 0x18, 0x48 };
const uint8_t ipn2[] = { 0x82, 0x02, 0x82, 0x18, 0x2a, 0x00 };
const uint8_t ipn3[] = { 0x82, 0x02, 0x82, 0x00, 0x00};
const uint8_t ipn4[] = {
0x82, 0x02, 0x82,
0x1b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x1b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
const uint8_t none[] = { 0x82, 0x01, 0x00 };
eid = bundle7_eid_parse(sat_1, sizeof(sat_1));
TEST_ASSERT_NOT_NULL(eid);
TEST_ASSERT_EQUAL_STRING("dtn:SAT1", eid);
eid = bundle7_eid_parse(ipn, sizeof(ipn));
TEST_ASSERT_NOT_NULL(eid);
TEST_ASSERT_EQUAL_STRING("ipn:42.72", eid);
eid = bundle7_eid_parse(ipn2, sizeof(ipn2));
TEST_ASSERT_NOT_NULL(eid);
TEST_ASSERT_EQUAL_STRING("ipn:42.0", eid);
eid = bundle7_eid_parse(ipn3, sizeof(ipn3));
TEST_ASSERT_NOT_NULL(eid);
TEST_ASSERT_EQUAL_STRING("ipn:0.0", eid);
eid = bundle7_eid_parse(ipn4, sizeof(ipn4));
TEST_ASSERT_NOT_NULL(eid);
TEST_ASSERT_EQUAL_STRING(
"ipn:18446744073709551615.18446744073709551615",
eid
);
eid = bundle7_eid_parse(none, sizeof(none));
TEST_ASSERT_NOT_NULL(eid);
TEST_ASSERT_EQUAL_STRING("dtn:none", eid);
}
static void parse_bundle_chunked(const size_t chunk_size)
{
struct bundle7_parser state;
struct parser *parser = bundle7_parser_init(
&state,
&send_callback,
NULL
);
TEST_ASSERT_NOT_NULL(parser);
size_t read = 0;
size_t chunk = chunk_size;
while (read < len_simple_bundle
&& state.basedata->status == PARSER_STATUS_GOOD) {
if (state.basedata->flags & PARSER_FLAG_BULK_READ) {
TEST_ASSERT_TRUE(read + state.basedata->next_bytes
< len_simple_bundle);
// Bulk read operation
memcpy(state.basedata->next_buffer,
cbor_simple_bundle + read,
state.basedata->next_bytes);
// Advance parsing pointer
read += state.basedata->next_bytes;
// Deactivate bulk read mode
state.basedata->flags &= ~PARSER_FLAG_BULK_READ;
} else {
if (chunk + read >= len_simple_bundle)
chunk = len_simple_bundle - read;
size_t parsed = bundle7_parser_read(&state,
cbor_simple_bundle + read,
chunk);
if (parsed == 0) {
chunk *= 2;
} else {
chunk = chunk_size;
read += parsed;
}
}
TEST_ASSERT_NOT_EQUAL(state.basedata->status,
PARSER_STATUS_ERROR);
}
TEST_ASSERT_EQUAL(PARSER_STATUS_DONE, state.basedata->status);
TEST_ASSERT_FALSE(state.basedata->flags & PARSER_FLAG_CRC_INVALID);
TEST_ASSERT_NULL(state.bundle);
TEST_ASSERT_NOT_NULL(bundle);
// Creation Timestamp 2020-11-12T09:51:03
TEST_ASSERT_EQUAL(658489863000, bundle->creation_timestamp_ms);
// Primary block CRC
TEST_ASSERT_EQUAL(BUNDLE_CRC_TYPE_NONE, bundle->crc_type);
// Bundle Processing flags
TEST_ASSERT_TRUE(bundle->proc_flags
& BUNDLE_FLAG_MUST_NOT_BE_FRAGMENTED);
TEST_ASSERT_TRUE(bundle->proc_flags
& BUNDLE_FLAG_REPORT_DELIVERY);
TEST_ASSERT_FALSE(bundle->proc_flags
& BUNDLE_FLAG_IS_FRAGMENT);
TEST_ASSERT_FALSE(bundle->proc_flags
& BUNDLE_FLAG_ADMINISTRATIVE_RECORD);
TEST_ASSERT_FALSE(bundle->proc_flags
& BUNDLE_FLAG_ACKNOWLEDGEMENT_REQUESTED);
TEST_ASSERT_FALSE(bundle->proc_flags
& BUNDLE_V6_FLAG_NORMAL_PRIORITY);
TEST_ASSERT_FALSE(bundle->proc_flags
& BUNDLE_V6_FLAG_EXPEDITED_PRIORITY);
TEST_ASSERT_FALSE(bundle->proc_flags
& BUNDLE_FLAG_REPORT_RECEPTION);
TEST_ASSERT_FALSE(bundle->proc_flags
& BUNDLE_FLAG_REPORT_FORWARDING);
TEST_ASSERT_FALSE(bundle->proc_flags
& BUNDLE_FLAG_REPORT_DELETION);
TEST_ASSERT_FALSE(bundle->proc_flags
& BUNDLE_FLAG_REPORT_STATUS_TIME);
struct bundle_block_list *block_element = bundle->blocks;
// Previous node block
TEST_ASSERT_EQUAL(BUNDLE_BLOCK_TYPE_PREVIOUS_NODE,
block_element->data->type);
TEST_ASSERT_EQUAL(BUNDLE_BLOCK_FLAG_NONE,
block_element->data->flags);
TEST_ASSERT_EQUAL(6, block_element->data->length);
uint8_t previous_node[6] = {
0x82, 0x01, 0x63, 0x47, 0x53, 0x34
};
TEST_ASSERT_EQUAL_INT8_ARRAY(previous_node,
block_element->data->data, 6);
TEST_ASSERT_EQUAL(BUNDLE_CRC_TYPE_NONE, block_element->data->crc_type);
// Hop count block
block_element = block_element->next;
TEST_ASSERT_EQUAL(BUNDLE_BLOCK_TYPE_HOP_COUNT,
block_element->data->type);
TEST_ASSERT_EQUAL(4, block_element->data->length);
uint8_t hop_count[4] = {
0x82, 0x18, 0x1e, 0x00
};
TEST_ASSERT_EQUAL_INT8_ARRAY(hop_count, block_element->data->data, 4);
TEST_ASSERT_EQUAL(BUNDLE_CRC_TYPE_NONE, block_element->data->crc_type);
// Bundle age block
block_element = block_element->next;
TEST_ASSERT_EQUAL(BUNDLE_BLOCK_TYPE_BUNDLE_AGE,
block_element->data->type);
TEST_ASSERT_EQUAL(1, block_element->data->length);
uint8_t bundle_age[1] = { 0x00 };
TEST_ASSERT_EQUAL_INT8_ARRAY(bundle_age, block_element->data->data, 1);
// Payload
block_element = block_element->next;
TEST_ASSERT_EQUAL_PTR(block_element->data,
bundle->payload_block);
// Payload block must be the last block
TEST_ASSERT_NULL(block_element->next);
uint8_t payload[] = {
'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!',
};
TEST_ASSERT_EQUAL(sizeof(payload), bundle->payload_block->length);
TEST_ASSERT_EQUAL_INT8_ARRAY(payload,
bundle->payload_block->data, 12);
TEST_ASSERT_EQUAL(BUNDLE_CRC_TYPE_NONE, block_element->data->crc_type);
TEST_ASSERT_EQUAL(len_simple_bundle,
bundle_get_serialized_size(bundle));
// Assert that serialized length is correct after recalculation
bundle_recalculate_header_length(bundle);
TEST_ASSERT_EQUAL(len_simple_bundle,
bundle_get_serialized_size(bundle));
}
TEST(bundle7Parser, bundle_parser)
{
for (size_t chunk = 1; chunk < len_simple_bundle; ++chunk) {
parse_bundle_chunked(chunk);
// Clear bundle
bundle_free(bundle);
bundle = NULL;
}
}
// -------------------------
// CRC 16 AX.25 Verification
// -------------------------
//
extern uint8_t cbor_crc16_primary_block[];
extern uint8_t cbor_crc16_payload_block[];
extern size_t len_crc16_primary_block;
extern size_t len_crc16_payload_block;
TEST(bundle7Parser, crc16_verification)
{
struct bundle7_parser state;
struct parser *parser = bundle7_parser_init(
&state,
&send_callback,
NULL
);
TEST_ASSERT_NOT_NULL(parser);
//
// CRC 16 primary block checksum
// -----------------------------
//
size_t parsed = bundle7_parser_read(&state, cbor_crc16_primary_block,
len_crc16_primary_block);
TEST_ASSERT_EQUAL(PARSER_STATUS_DONE, state.basedata->status);
TEST_ASSERT_FALSE(state.basedata->flags & PARSER_FLAG_CRC_INVALID);
TEST_ASSERT_EQUAL(parsed, len_crc16_primary_block);
TEST_ASSERT_NULL(state.bundle);
TEST_ASSERT_NOT_NULL(bundle);
TEST_ASSERT_EQUAL(bundle->crc.checksum, 0x7123);
// Clear bundle
bundle_free(bundle);
bundle = NULL;
//
// CRC 16 payload block checksum
// -----------------------------
//
bundle7_parser_reset(&state);
parsed = bundle7_parser_read(&state, cbor_crc16_payload_block,
len_crc16_payload_block);
TEST_ASSERT_EQUAL(PARSER_STATUS_DONE, state.basedata->status);
TEST_ASSERT_FALSE(state.basedata->flags & PARSER_FLAG_CRC_INVALID);
TEST_ASSERT_EQUAL(parsed, len_crc16_payload_block);
TEST_ASSERT_NULL(state.bundle);
TEST_ASSERT_NOT_NULL(bundle);
TEST_ASSERT_EQUAL(bundle->payload_block->crc.checksum, 0x60d7);
// Clear bundle
bundle_free(bundle);
bundle = NULL;
}
// ------------------------------
// CRC 32 Castagnoli Verification
// ------------------------------
//
extern uint8_t cbor_crc32_primary_block[];
extern uint8_t cbor_crc32_payload_block[];
extern size_t len_crc32_primary_block;
extern size_t len_crc32_payload_block;
TEST(bundle7Parser, crc32_verification)
{
struct bundle7_parser state;
struct parser *parser = bundle7_parser_init(
&state,
&send_callback,
NULL
);
TEST_ASSERT_NOT_NULL(parser);
//
// CRC 32 primary block checksum
// -----------------------------
//
size_t parsed = bundle7_parser_read(&state, cbor_crc32_primary_block,
len_crc32_primary_block);
TEST_ASSERT_EQUAL(PARSER_STATUS_DONE, state.basedata->status);
TEST_ASSERT_FALSE(state.basedata->flags & PARSER_FLAG_CRC_INVALID);
TEST_ASSERT_EQUAL(parsed, len_crc32_primary_block);
TEST_ASSERT_NULL(state.bundle);
TEST_ASSERT_NOT_NULL(bundle);
TEST_ASSERT_EQUAL(bundle->crc.checksum, 0x9542defd);
// Clear bundle
bundle_free(bundle);
bundle = NULL;
//
// CRC 32 payload block checksum
// -----------------------------
//
bundle7_parser_reset(&state);
parsed = bundle7_parser_read(&state, cbor_crc32_payload_block,
len_crc32_payload_block);
TEST_ASSERT_EQUAL(PARSER_STATUS_DONE, state.basedata->status);
TEST_ASSERT_FALSE(state.basedata->flags & PARSER_FLAG_CRC_INVALID);
TEST_ASSERT_EQUAL(parsed, len_crc32_payload_block);
TEST_ASSERT_NULL(state.bundle);
TEST_ASSERT_NOT_NULL(bundle);
TEST_ASSERT_EQUAL(bundle->payload_block->crc.checksum, 0xc3aec552);
// Clear bundle
bundle_free(bundle);
bundle = NULL;
}
// --------------------
// Invalid CRC Handling
// --------------------
extern uint8_t cbor_invalid_crc16[];
extern size_t len_invalid_crc16;
TEST(bundle7Parser, invalid_crc_handling)
{
struct bundle7_parser state;
struct parser *parser = bundle7_parser_init(
&state,
&send_callback,
NULL
);
TEST_ASSERT_NOT_NULL(parser);
size_t parsed = bundle7_parser_read(&state, cbor_invalid_crc16,
len_invalid_crc16);
// The bundle must be parsed completely
TEST_ASSERT_EQUAL(PARSER_STATUS_DONE, state.basedata->status);
TEST_ASSERT_EQUAL(parsed, len_invalid_crc16);
// but the CRC_INVALID flag must be set
TEST_ASSERT_TRUE(state.basedata->flags & PARSER_FLAG_CRC_INVALID);
// and the bundle must not be send callback must not be called
TEST_ASSERT_NULL(state.bundle);
TEST_ASSERT_NULL(bundle);
}
static const uint8_t cbor_status_report[] = {
// [
// 1, // Record type code
// [
// [ // bundle status information
// [true, 10], // Reporting node received bundle
// [false], // Reporting node forwarded the bundle
// [false], // Reporting node delivered the bundle
// [false] // Reporting node deleted the bundle
// ],
// 0, // bundle status report reason code
// [1, 0], // Source node ID of reported bundle
// [2165, 12] // Creation time of the reported bundle
// ]
// ]
// ]
0x82, 0x01, 0x84, 0x84, 0x82, 0xf5, 0x0a, 0x81, 0xf4, 0x81,
0xf4, 0x81, 0xf4, 0x00, 0x82, 0x01, 0x00, 0x82, 0x19, 0x08, 0x75, 0x0c
};
TEST(bundle7Parser, status_report_parser)
{
struct bundle *bundle = bundle_init();
TEST_ASSERT_NOT_NULL(bundle);
// Primary Block
bundle->proc_flags = BUNDLE_FLAG_REPORT_STATUS_TIME
| BUNDLE_FLAG_ADMINISTRATIVE_RECORD;
bundle->creation_timestamp_ms = 4200;
bundle->sequence_number = 0;
bundle->lifetime_ms = 86400;
struct bundle_block *payload;
struct bundle_block_list *entry;
// Payload
payload = bundle_block_create(BUNDLE_BLOCK_TYPE_PAYLOAD);
entry = bundle_block_entry_create(payload);
payload->length = sizeof(cbor_status_report);
payload->data = malloc(payload->length);
memcpy(payload->data, cbor_status_report, sizeof(cbor_status_report));
bundle->blocks = entry;
bundle->payload_block = payload;
// Parser payload
struct bundle_administrative_record *record =
bundle7_parse_administrative_record(
bundle->payload_block->data,
bundle->payload_block->length
);
TEST_ASSERT_NOT_NULL(record);
TEST_ASSERT_NOT_NULL(record->status_report);
TEST_ASSERT_EQUAL(BUNDLE_AR_STATUS_REPORT, record->type);
TEST_ASSERT_EQUAL(0, record->flags);
TEST_ASSERT_EQUAL(2165, record->bundle_creation_timestamp_ms);
TEST_ASSERT_EQUAL(12, record->bundle_sequence_number);
TEST_ASSERT_EQUAL(10, record->status_report->bundle_received_time);
TEST_ASSERT_EQUAL(BUNDLE_SR_FLAG_BUNDLE_RECEIVED,
record->status_report->status);
TEST_ASSERT_EQUAL(BUNDLE_SR_REASON_NO_INFO,
record->status_report->reason);
// free_administrative_record(record);
bundle_free(bundle);
}
// [30, 4]
static const uint8_t cbor_hop_count[] = { 0x82, 0x18, 0x1e, 0x04 };
TEST(bundle7Parser, hop_count)
{
struct bundle_hop_count hop_count;
// Try to parse empty buffer
TEST_ASSERT_FALSE(bundle7_hop_count_parse(&hop_count, NULL, 0));
// Try to parse wrong CBOR structure
TEST_ASSERT_FALSE(bundle7_hop_count_parse(&hop_count,
cbor_status_report, sizeof(cbor_status_report)));
// Parse valid CBOR structure
TEST_ASSERT_TRUE(bundle7_hop_count_parse(&hop_count,
cbor_hop_count, sizeof(cbor_hop_count)));
TEST_ASSERT_EQUAL(30, hop_count.limit);
TEST_ASSERT_EQUAL(4, hop_count.count);
}
// 42000
static const uint8_t cbor_bundle_age[] = { 0x19, 0xa4, 0x10 };
TEST(bundle7Parser, bundle_age)
{
uint64_t bundle_age;
// Try to parse empty buffer
TEST_ASSERT_FALSE(bundle_age_parse(&bundle_age, NULL, 0));
// Try to parse wrong CBOR structure
TEST_ASSERT_FALSE(bundle_age_parse(&bundle_age,
cbor_status_report, sizeof(cbor_status_report)));
// Parse valid CBOR structure
TEST_ASSERT_TRUE(bundle_age_parse(&bundle_age,
cbor_bundle_age, sizeof(cbor_bundle_age)));
TEST_ASSERT_EQUAL(42000, bundle_age);
}
TEST_GROUP_RUNNER(bundle7Parser)
{
RUN_TEST_CASE(bundle7Parser, eid_parser);
RUN_TEST_CASE(bundle7Parser, bundle_parser);
RUN_TEST_CASE(bundle7Parser, crc16_verification);
RUN_TEST_CASE(bundle7Parser, crc32_verification);
RUN_TEST_CASE(bundle7Parser, invalid_crc_handling);
RUN_TEST_CASE(bundle7Parser, status_report_parser);
RUN_TEST_CASE(bundle7Parser, hop_count);
RUN_TEST_CASE(bundle7Parser, bundle_age);
}