diff options
Diffstat (limited to 'libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_OptionalHeadersDecoder.c')
-rw-r--r-- | libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_OptionalHeadersDecoder.c | 321 |
1 files changed, 321 insertions, 0 deletions
diff --git a/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_OptionalHeadersDecoder.c b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_OptionalHeadersDecoder.c new file mode 100644 index 00000000..abe47608 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/schema_v1/test/test_ccnxCodecSchemaV1_OptionalHeadersDecoder.c @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../ccnxCodecSchemaV1_OptionalHeadersDecoder.c" +#include <parc/algol/parc_SafeMemory.h> + +#include <inttypes.h> + +#include <LongBow/unit-test.h> + +typedef struct test_data { + PARCBuffer *optionalHeader; + CCNxCodecTlvDecoder *decoder; + CCNxTlvDictionary *dictionary; + + // truth table + PARCBuffer *interestLifetime; + PARCBuffer *cacheTime; + PARCBuffer *interestFrag; + PARCBuffer *objectFrag; + PARCBuffer *customHeader; + + // the key for the customHeader + uint16_t customHeaderType; +} TestData; + +/** + * A packet with all the defined optional headers plus one custom header + * This is not actually a packet one would see in real life as it has + * headers from both an Interest and a Content Object + */ +static uint8_t packet_with_headers[] = { + 0x01, 0x01, 0x00, 120, // ver = 1, type = interest, length = 120 + 0x01, 0x00, 0x00, 88, // hopLimit = 1, reserved = 0, header length = 88 + // ------------------------ + // byte 8 + 0x00, 0x01, 0x00, 0x08, // Interest Lifetime (type 1) + 0x20, 0x30, 0x40, 0x50, // 0x2030405060708090 + 0x60, 0x70, 0x80, 0x90, + // ------------------------ + // byte 20 + 0x00, 0x02, 0x00, 0x08, // Recommended Cache Time (type 2) + 0x21, 0x31, 0x41, 0x51, // 0x2030405060708090 + 0x61, 0x71, 0x81, 0x91, + // ------------------------ + // byte 32 + 0x00, 0x03, 0x00, 0x0C, // Interest Fragment (type 3) + 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, 0x07, 0x08, // fragment 0x0102030405060708 + 0x05, 0xDC, 0x04, 0x00, // MTU 1500, fragcnt 4, fragnum 0 + // ------------------------ + // byte 48 + 0x00, 0x04, 0x00, 20, // ContentObject Fragment (type 4) + 0xC1, 0xC2, 0xC3, 0xC4, + 0xC5, 0xC6, 0xC7, 0xC8, // fragment 0xC1C2C3C4C5C6C7C8 + 0x05, 0xDC, 0x04, 0x00, // MTU 1500, fragcnt 4, fragnum 0 + 0xD1, 0xD2, 0xD3, 0xD4, + 0xD5, 0xD6, 0xD7, 0xD8, // fragment 0xD1D2D3D4D5D6D7D8 + // ------------------------ + // byte 72 + 0x01, 0x00, 0x00, 12, // Custom header (type 256), length 12 + 0xA0, 0xA1, 0xA2, 0xA3, + 0xA4, 0xA5, 0xA6, 0xA7, + 0xA8, 0xA9, 0xAA, 0xAB, + // ------------------------ + // byte 88 + 0x00, 0x01, 0x00, 29, // type = interest, length = 29 + // ------------------------ + 0x00, 0x00, 0x00, 0x10, // type = name, length = 16 + 0x00, 0x02, 0x00, 0x04, // type = binary, length = 5 + 'h', 'e', 'l', 'l', // "hello" + 0xF0, 0x00, 0x00, 0x04, // type = app, length = 4 + 'o', 'u', 'c', 'h', // "ouch" + // ------------------------ + 0x00, 0x01, 0x00, 0x04, // type = keyid, length = 4 + 0xA0, 0xB0, 0xC0, 0xD0, // 0xA0B0C0D0 + // ------------------------ + // byte 120 +}; + +static TestData * +_commonSetup(void) +{ + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData)); + + // setup the decoder and decode the optional headers + data->optionalHeader = parcBuffer_Wrap(packet_with_headers, sizeof(packet_with_headers), 8, 88); + data->decoder = ccnxCodecTlvDecoder_Create(data->optionalHeader); + data->dictionary = ccnxTlvDictionary_Create(10, 5); + + // setup the truth values + data->interestLifetime = parcBuffer_Wrap(packet_with_headers, sizeof(packet_with_headers), 12, 20); + data->cacheTime = parcBuffer_Wrap(packet_with_headers, sizeof(packet_with_headers), 24, 32); + + data->interestFrag = parcBuffer_Wrap(packet_with_headers, sizeof(packet_with_headers), 36, 48); + data->objectFrag = parcBuffer_Wrap(packet_with_headers, sizeof(packet_with_headers), 52, 72); + + data->customHeader = parcBuffer_Wrap(packet_with_headers, sizeof(packet_with_headers), 76, 88); + data->customHeaderType = 0x0100; + + return data; +} + +static void +_commonTeardown(TestData *data) +{ + ccnxTlvDictionary_Release(&data->dictionary); + ccnxCodecTlvDecoder_Destroy(&data->decoder); + parcBuffer_Release(&data->optionalHeader); + + parcBuffer_Release(&data->interestLifetime); + parcBuffer_Release(&data->cacheTime); + parcBuffer_Release(&data->interestFrag); + parcBuffer_Release(&data->objectFrag); + parcBuffer_Release(&data->customHeader); + + parcMemory_Deallocate((void **) &data); +} + +LONGBOW_TEST_RUNNER(ccnxCodecSchemaV1_OptionalHeadersDecoder) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(ccnxCodecSchemaV1_OptionalHeadersDecoder) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(ccnxCodecSchemaV1_OptionalHeadersDecoder) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_Decode_TooLong); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetContentObjectFragmentHeader); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestFragmentHeader); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestLifetimeHeader); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetRecommendedCacheTimeHeader); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetCustomHeader); + + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetContentObjectFragmentHeader_Missing); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestFragmentHeader_Missing); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestLifetimeHeader_Missing); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetRecommendedCacheTimeHeader_Missing); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetCustomHeader_Missing); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + longBowTestCase_SetClipBoardData(testCase, _commonSetup()); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + _commonTeardown(longBowTestCase_GetClipBoardData(testCase)); + + uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO); + if (outstandingAllocations != 0) { + printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +/** + * One of the TLVs will extend beyond the end of the buffer. Should fail. + */ +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_Decode_TooLong) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + // Make one of the fields 255 bytes + uint8_t original = packet_with_headers[10]; + packet_with_headers[10] = 0xFF; + bool success = ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(data->decoder, data->dictionary); + + // now set it back + packet_with_headers[10] = original; + + assertFalse(success, "Should have failed to parse when a TLV exceeds bounary"); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetContentObjectFragmentHeader) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(data->decoder, data->dictionary); + PARCBuffer *test = ccnxCodecSchemaV1OptionalHeadersDecoder_GetContentObjectFragmentHeader(data->dictionary); + assertTrue(parcBuffer_Equals(test, data->objectFrag), "Wrong value") + { + printf("Expected: \n"); + parcBuffer_Display(data->objectFrag, 3); + printf("Got:\n"); + parcBuffer_Display(test, 3); + } +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestFragmentHeader) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(data->decoder, data->dictionary); + PARCBuffer *test = ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestFragmentHeader(data->dictionary); + assertTrue(parcBuffer_Equals(test, data->interestFrag), "Wrong value") + { + printf("Expected: \n"); + parcBuffer_Display(data->interestFrag, 3); + printf("Got:\n"); + parcBuffer_Display(test, 3); + } +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestLifetimeHeader) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(data->decoder, data->dictionary); + uint64_t lifetime = ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestLifetimeHeader(data->dictionary); + + uint64_t trueLifetime = 0; + ccnxCodecTlvUtilities_GetVarInt(data->interestLifetime, parcBuffer_Remaining(data->interestLifetime), &trueLifetime); + + assertTrue(trueLifetime == lifetime, "wrong value, expected %" PRIx64 " got %" PRIx64, trueLifetime, lifetime); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetRecommendedCacheTimeHeader) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(data->decoder, data->dictionary); + uint64_t cachetime = ccnxCodecSchemaV1OptionalHeadersDecoder_GetRecommendedCacheTimeHeader(data->dictionary); + + uint64_t trueCachetime = 0; + ccnxCodecTlvUtilities_GetVarInt(data->cacheTime, parcBuffer_Remaining(data->cacheTime), &trueCachetime); + + assertTrue(trueCachetime == cachetime, "wrong value, expected %" PRIx64 " got %" PRIx64, trueCachetime, cachetime); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetCustomHeader) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + ccnxCodecSchemaV1OptionalHeadersDecoder_Decode(data->decoder, data->dictionary); + PARCBuffer *test = ccnxCodecSchemaV1OptionalHeadersDecoder_GetCustomType(data->dictionary, data->customHeaderType); + assertTrue(parcBuffer_Equals(test, data->customHeader), "Wrong value for header type %02X", data->customHeaderType) + { + printf("Expected: \n"); + parcBuffer_Display(data->customHeader, 3); + printf("Got:\n"); + parcBuffer_Display(test, 3); + } +} + +// ======== +// test for missing values + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetContentObjectFragmentHeader_Missing) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *test = ccnxCodecSchemaV1OptionalHeadersDecoder_GetContentObjectFragmentHeader(data->dictionary); + assertNull(test, "Did not get null buffer for missing field, got %p", (void *) test); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestFragmentHeader_Missing) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *test = ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestFragmentHeader(data->dictionary); + assertNull(test, "Did not get null buffer for missing field, got %p", (void *) test); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetInterestLifetimeHeader_Missing) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + bool exists = ccnxTlvDictionary_IsValueInteger(data->dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_InterestLifetime); + assertFalse(exists, "Dictionary reports it has a missing field"); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetRecommendedCacheTimeHeader_Missing) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + bool exists = ccnxTlvDictionary_IsValueInteger(data->dictionary, CCNxCodecSchemaV1TlvDictionary_HeadersFastArray_RecommendedCacheTime); + assertFalse(exists, "Dictionary reports it has a missing field"); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecSchemaV1OptionalHeadersDecoder_GetCustomHeader_Missing) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + PARCBuffer *test = ccnxCodecSchemaV1OptionalHeadersDecoder_GetCustomType(data->dictionary, data->customHeaderType); + assertNull(test, "Did not get null buffer for missing field, got %p", (void *) test); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnxCodecSchemaV1_OptionalHeadersDecoder); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} |