ud3tn/test/unit/test_bundle7Serializer.c

590 lines
14 KiB
C
Raw Permalink Normal View History

// SPDX-License-Identifier: BSD-3-Clause OR Apache-2.0
/**
* Unit Test for BPbis serializer
*
* Raw CBOR data is loaded from "test_bundle7Data.c".
*/
#include "bundle7/serializer.h"
#include "bundle7/eid.h"
#include "bundle7/hopcount.h"
#include "bundle7/bundle_age.h"
#include "bundle7/bundle7.h"
#include "platform/hal_io.h"
#include "ud3tn/bundle.h"
#include "ud3tn/result.h"
#include "testud3tn_unity.h"
#include <stddef.h>
#include <stdlib.h> // malloc(), free()
#include <string.h> // memcpy()
TEST_GROUP(bundle7Serializer);
extern uint8_t cbor_simple_bundle[];
extern size_t len_simple_bundle;
static size_t output_bytes;
TEST_SETUP(bundle7Serializer)
{
output_bytes = 0;
}
TEST_TEAR_DOWN(bundle7Serializer)
{
}
static enum ud3tn_result write(void *cla_obj, const void *data,
const size_t len)
{
char buf[32];
TEST_ASSERT_TRUE_MESSAGE(
output_bytes + len <= len_simple_bundle,
"CBOR too long");
snprintf(buf, sizeof(buf), "Offset was: %zu", output_bytes);
if (len)
TEST_ASSERT_EQUAL_INT8_ARRAY_MESSAGE(
cbor_simple_bundle + output_bytes,
data, len, buf);
output_bytes += len;
return UD3TN_OK;
}
static struct bundle *create_simple_bundle(void)
{
struct bundle *bundle = bundle_init();
TEST_ASSERT_NOT_NULL(bundle);
bundle->protocol_version = 7;
bundle->proc_flags = BUNDLE_FLAG_MUST_NOT_BE_FRAGMENTED
| BUNDLE_FLAG_REPORT_DELIVERY
// this is a RFC 5050 flag and should be ignored
// by the serializer
| BUNDLE_V6_FLAG_NORMAL_PRIORITY;
bundle->crc_type = BUNDLE_CRC_TYPE_NONE;
bundle->destination = strdup("dtn:GS2");
bundle->source = strdup("ipn:243.350");
bundle->report_to = strdup("dtn:none");
bundle->creation_timestamp_ms = 658489863000; // 2020-11-12T09:51:03
bundle->sequence_number = 0;
bundle->lifetime_ms = 86400;
struct bundle_block_list *prev;
struct bundle_block_list *entry;
struct bundle_block *block;
// Previous node block
block = bundle_block_create(BUNDLE_BLOCK_TYPE_PREVIOUS_NODE);
entry = bundle_block_entry_create(block);
bundle->blocks = entry;
prev = entry;
// CBOR: [1, "GS4"]
uint8_t previous_node[6] = {
0x82, 0x01, 0x63, 0x47, 0x53, 0x34
};
block->number = 2;
block->crc_type = BUNDLE_CRC_TYPE_NONE;
block->length = sizeof(previous_node);
block->data = malloc(sizeof(previous_node));
TEST_ASSERT_NOT_NULL(block->data);
memcpy(block->data, previous_node, sizeof(previous_node));
// Hop count block
block = bundle_block_create(BUNDLE_BLOCK_TYPE_HOP_COUNT);
entry = bundle_block_entry_create(block);
prev->next = entry;
prev = entry;
// CBOR: [30, 0]
uint8_t hop_count[4] = { 0x82, 0x18, 0x1e, 0x00 };
block->number = 3;
block->crc_type = BUNDLE_CRC_TYPE_NONE;
block->length = sizeof(hop_count);
block->data = malloc(sizeof(hop_count));
TEST_ASSERT_NOT_NULL(block->data);
memcpy(block->data, hop_count, sizeof(hop_count));
// Bundle age block
block = bundle_block_create(BUNDLE_BLOCK_TYPE_BUNDLE_AGE);
entry = bundle_block_entry_create(block);
prev->next = entry;
prev = entry;
// CBOR: 0
uint8_t bundle_age[1] = { 0x00 };
block->number = 4;
block->crc_type = BUNDLE_CRC_TYPE_NONE;
block->length = sizeof(bundle_age);
block->data = malloc(sizeof(bundle_age));
TEST_ASSERT_NOT_NULL(block->data);
memcpy(block->data, bundle_age, sizeof(bundle_age));
// Payload
block = bundle_block_create(BUNDLE_BLOCK_TYPE_PAYLOAD);
entry = bundle_block_entry_create(block);
prev->next = entry;
uint8_t payload[12] = {
'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!',
};
TEST_ASSERT_EQUAL(1, block->number);
block->crc_type = BUNDLE_CRC_TYPE_NONE;
block->length = sizeof(payload);
block->data = malloc(sizeof(payload));
TEST_ASSERT_NOT_NULL(block->data);
memcpy(block->data, payload, sizeof(payload));
bundle->payload_block = block;
return bundle;
}
TEST(bundle7Serializer, simple_bundle)
{
struct bundle *bundle = create_simple_bundle();
TEST_ASSERT_EQUAL(UD3TN_OK, bundle7_serialize(bundle, write, NULL));
TEST_ASSERT_EQUAL(len_simple_bundle, output_bytes);
bundle_free(bundle);
}
static enum ud3tn_result write_fail(void *cla_obj, const void *data,
const size_t len)
{
output_bytes++; // Here we just use it as a counter.
return UD3TN_FAIL;
}
TEST(bundle7Serializer, write_fail)
{
struct bundle *bundle = create_simple_bundle();
TEST_ASSERT_EQUAL(UD3TN_FAIL,
bundle7_serialize(bundle, write_fail, NULL));
// Assert write_fail was only called once.
TEST_ASSERT_EQUAL(1, output_bytes);
bundle_free(bundle);
}
// -----------------------
// CRC 16 AX.25 Generation
// -----------------------
//
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;
static enum ud3tn_result write_crc16_primary_block(
void *cla_obj, const void *data,
const size_t len)
{
char buf[32];
TEST_ASSERT_TRUE_MESSAGE(
output_bytes + len <= len_crc16_primary_block,
"CBOR too long");
snprintf(buf, sizeof(buf), "Offset was: %zu", output_bytes);
if (len)
TEST_ASSERT_EQUAL_INT8_ARRAY_MESSAGE(
cbor_crc16_primary_block + output_bytes,
data, len, buf);
output_bytes += len;
return UD3TN_OK;
}
static enum ud3tn_result write_crc16_payload_block(
void *cla_obj, const void *data,
const size_t len)
{
char buf[32];
TEST_ASSERT_TRUE_MESSAGE(
output_bytes + len <= len_crc16_payload_block,
"CBOR too long");
snprintf(buf, sizeof(buf), "Offset was: %zu", output_bytes);
if (len)
TEST_ASSERT_EQUAL_INT8_ARRAY_MESSAGE(
cbor_crc16_payload_block + output_bytes,
data, len, buf);
output_bytes += len;
return UD3TN_OK;
}
TEST(bundle7Serializer, crc16_generation)
{
// --------------------
// CRC-16 primary block
// --------------------
struct bundle *bundle = bundle_init();
TEST_ASSERT_NOT_NULL(bundle);
bundle->protocol_version = 7;
bundle->proc_flags = BUNDLE_FLAG_NONE;
bundle->crc_type = BUNDLE_CRC_TYPE_16;
bundle->destination = strdup("dtn:GS2");
bundle->source = strdup("dtn:none");
bundle->report_to = strdup("dtn:none");
bundle->creation_timestamp_ms = 0;
bundle->sequence_number = 0;
bundle->lifetime_ms = 86400;
struct bundle_block *block;
// Empty Payload
block = bundle_block_create(BUNDLE_BLOCK_TYPE_PAYLOAD);
bundle->blocks = bundle_block_entry_create(block);
block->number = 0;
block->crc_type = BUNDLE_CRC_TYPE_NONE;
block->length = 0;
block->data = NULL;
bundle->payload_block = block;
TEST_ASSERT_EQUAL(UD3TN_OK,
bundle7_serialize(bundle, write_crc16_primary_block, NULL));
TEST_ASSERT_EQUAL(len_crc16_primary_block, output_bytes);
// --------------------
// CRC-16 payload block
// --------------------
// Replace payload
free(block->data);
const uint8_t payload[] = {
'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!',
};
block->crc_type = BUNDLE_CRC_TYPE_16;
block->length = sizeof(payload);
block->data = malloc(sizeof(payload));
TEST_ASSERT_NOT_NULL(block->data);
memcpy(block->data, payload, sizeof(payload));
// Disable CRC for primary block
bundle->crc_type = BUNDLE_CRC_TYPE_NONE;
// Reset output counter
output_bytes = 0;
TEST_ASSERT_EQUAL(UD3TN_OK,
bundle7_serialize(bundle, write_crc16_payload_block, NULL));
TEST_ASSERT_EQUAL(len_crc16_payload_block, output_bytes);
bundle_free(bundle);
}
// --------------------------
// CRC 32 Ethernet Generation
// --------------------------
//
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;
static enum ud3tn_result write_crc32_primary_block(
void *cla_obj, const void *data,
const size_t len)
{
char buf[32];
TEST_ASSERT_TRUE_MESSAGE(
output_bytes + len <= len_crc32_primary_block,
"CBOR too long");
snprintf(buf, sizeof(buf), "Offset was: %zu", output_bytes);
if (len)
TEST_ASSERT_EQUAL_INT8_ARRAY_MESSAGE(
cbor_crc32_primary_block + output_bytes,
data, len, buf);
output_bytes += len;
return UD3TN_OK;
}
static enum ud3tn_result write_crc32_payload_block(
void *cla_obj, const void *data,
const size_t len)
{
char buf[32];
TEST_ASSERT_TRUE_MESSAGE(
output_bytes + len <= len_crc32_payload_block,
"CBOR too long");
snprintf(buf, sizeof(buf), "Offset was: %zu", output_bytes);
if (len)
TEST_ASSERT_EQUAL_INT8_ARRAY_MESSAGE(
cbor_crc32_payload_block + output_bytes,
data, len, buf);
output_bytes += len;
return UD3TN_OK;
}
TEST(bundle7Serializer, crc32_generation)
{
// --------------------
// CRC-32 primary block
// --------------------
struct bundle *bundle = bundle_init();
TEST_ASSERT_NOT_NULL(bundle);
bundle->protocol_version = 7;
bundle->proc_flags = BUNDLE_FLAG_NONE;
bundle->crc_type = BUNDLE_CRC_TYPE_32;
bundle->destination = strdup("dtn:GS2");
bundle->source = strdup("dtn:none");
bundle->report_to = strdup("dtn:none");
bundle->creation_timestamp_ms = 0;
bundle->sequence_number = 0;
bundle->lifetime_ms = 86400;
struct bundle_block *block;
// Empty Payload
block = bundle_block_create(BUNDLE_BLOCK_TYPE_PAYLOAD);
bundle->blocks = bundle_block_entry_create(block);
block->number = 0;
block->crc_type = BUNDLE_CRC_TYPE_NONE;
block->length = 0;
block->data = NULL;
bundle->payload_block = block;
TEST_ASSERT_EQUAL(UD3TN_OK,
bundle7_serialize(bundle, write_crc32_primary_block, NULL));
TEST_ASSERT_EQUAL(len_crc32_primary_block, output_bytes);
// --------------------
// CRC-32 payload block
// --------------------
// Replace payload
free(block->data);
const uint8_t payload[] = {
'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!',
};
block->crc_type = BUNDLE_CRC_TYPE_32;
block->length = sizeof(payload);
block->data = malloc(sizeof(payload));
TEST_ASSERT_NOT_NULL(block->data);
memcpy(block->data, payload, sizeof(payload));
// Disable CRC for primary block
bundle->crc_type = BUNDLE_CRC_TYPE_NONE;
// Reset output counter
output_bytes = 0;
TEST_ASSERT_EQUAL(UD3TN_OK,
bundle7_serialize(bundle, write_crc32_payload_block, NULL));
TEST_ASSERT_EQUAL(len_crc32_payload_block, output_bytes);
bundle_free(bundle);
}
static uint8_t cbor_dtn_text[6] = { 0x82, 0x01, 0x63, 0x47, 0x53, 0x31 };
TEST(bundle7Serializer, dtn_text)
{
size_t length;
uint8_t *buffer;
buffer = bundle7_eid_serialize_alloc("dtn:GS1", &length);
TEST_ASSERT_NOT_NULL(buffer);
TEST_ASSERT_EQUAL(sizeof(cbor_dtn_text), length);
TEST_ASSERT_EQUAL_INT8_ARRAY(cbor_dtn_text, buffer,
sizeof(cbor_dtn_text));
}
static const uint8_t dtn_none[] = { 0x82, 0x01, 0x00 };
TEST(bundle7Serializer, dtn_none)
{
size_t length;
uint8_t *buffer;
buffer = bundle7_eid_serialize_alloc("dtn:none", &length);
TEST_ASSERT_NOT_NULL(buffer);
TEST_ASSERT_EQUAL(sizeof(dtn_none), length);
buffer = bundle7_eid_serialize_alloc("", &length);
TEST_ASSERT_NOT_NULL(buffer);
TEST_ASSERT_EQUAL(sizeof(dtn_none), length);
buffer = bundle7_eid_serialize_alloc(NULL, &length);
TEST_ASSERT_NOT_NULL(buffer);
TEST_ASSERT_EQUAL(sizeof(dtn_none), length);
TEST_ASSERT_EQUAL_INT8_ARRAY(dtn_none, buffer,
sizeof(dtn_none));
}
// ipn:12.123
static const uint8_t dtn_ipn[] = { 0x82, 0x02, 0x82, 0x0c, 0x18, 0x7b };
static const char *const dtn_ipn_eid = "ipn:12.123";
// max. value for ipn: EID
static const uint8_t dtn_ipn2[] = {
0x82, 0x02, 0x82,
0x1B, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x1B, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
static const char *const dtn_ipn2_eid =
"ipn:18446744073709551615.18446744073709551615";
static const char *const dtn_ipn_overflow1_eid =
"ipn:18446744073709551616.18446744073709551615";
static const char *const dtn_ipn_overflow2_eid =
"ipn:18446744073709551615.18446744073709551616";
TEST(bundle7Serializer, dtn_ipn)
{
size_t length;
uint8_t *buffer;
buffer = bundle7_eid_serialize_alloc(dtn_ipn_eid, &length);
TEST_ASSERT_NOT_NULL(buffer);
TEST_ASSERT_EQUAL(sizeof(dtn_ipn), length);
TEST_ASSERT_EQUAL_UINT8_ARRAY(dtn_ipn, buffer,
sizeof(dtn_ipn));
TEST_ASSERT_EQUAL(length, bundle7_eid_sizeof(dtn_ipn_eid));
free(buffer);
buffer = bundle7_eid_serialize_alloc(
dtn_ipn2_eid,
&length
);
TEST_ASSERT_NOT_NULL(buffer);
TEST_ASSERT_EQUAL(sizeof(dtn_ipn2), length);
TEST_ASSERT_EQUAL_UINT8_ARRAY(dtn_ipn2, buffer,
sizeof(dtn_ipn2));
TEST_ASSERT_EQUAL(length, bundle7_eid_sizeof(dtn_ipn2_eid));
free(buffer);
buffer = bundle7_eid_serialize_alloc(
dtn_ipn_overflow1_eid,
&length
);
TEST_ASSERT_EQUAL(0, bundle7_eid_sizeof(dtn_ipn_overflow1_eid));
TEST_ASSERT_NULL(buffer);
buffer = bundle7_eid_serialize_alloc(
dtn_ipn_overflow2_eid,
&length
);
TEST_ASSERT_EQUAL(0, bundle7_eid_sizeof(dtn_ipn_overflow2_eid));
TEST_ASSERT_NULL(buffer);
}
// [40, 10]
static const uint8_t cbor_hop_count[] = { 0x82, 0x18, 0x28, 0x0a };
TEST(bundle7Serializer, hop_count)
{
struct bundle_hop_count hop_count = {
.limit = 40,
.count = 10
};
uint8_t *buffer = malloc(BUNDLE7_HOP_COUNT_MAX_ENCODED_SIZE);
TEST_ASSERT_NOT_NULL(buffer)
size_t written = bundle7_hop_count_serialize(
&hop_count, buffer, BUNDLE7_HOP_COUNT_MAX_ENCODED_SIZE);
TEST_ASSERT_EQUAL(sizeof(cbor_hop_count), written);
TEST_ASSERT_EQUAL_INT8_ARRAY(cbor_hop_count, buffer,
sizeof(cbor_hop_count));
}
// 42000
static const uint8_t cbor_bundle_age[] = { 0x19, 0xa4, 0x10 };
TEST(bundle7Serializer, bundle_age)
{
uint64_t bundle_age = 42000;
uint8_t *buffer = malloc(BUNDLE_AGE_MAX_ENCODED_SIZE);
TEST_ASSERT_NOT_NULL(buffer);
size_t written = bundle_age_serialize(bundle_age, buffer,
BUNDLE_AGE_MAX_ENCODED_SIZE);
TEST_ASSERT_EQUAL(sizeof(cbor_bundle_age), written);
TEST_ASSERT_EQUAL_INT8_ARRAY(cbor_bundle_age, buffer,
sizeof(cbor_bundle_age));
}
TEST_GROUP_RUNNER(bundle7Serializer)
{
RUN_TEST_CASE(bundle7Serializer, dtn_text);
RUN_TEST_CASE(bundle7Serializer, dtn_none);
RUN_TEST_CASE(bundle7Serializer, dtn_ipn);
RUN_TEST_CASE(bundle7Serializer, hop_count);
RUN_TEST_CASE(bundle7Serializer, bundle_age);
RUN_TEST_CASE(bundle7Serializer, simple_bundle);
RUN_TEST_CASE(bundle7Serializer, write_fail);
RUN_TEST_CASE(bundle7Serializer, crc16_generation);
RUN_TEST_CASE(bundle7Serializer, crc32_generation);
}