diff options
author | Michele Papalini <micpapal+fdio@cisco.com> | 2017-02-24 08:00:13 +0000 |
---|---|---|
committer | Gerrit Code Review <gerrit@fd.io> | 2017-02-24 08:00:13 +0000 |
commit | 6d4b6878ceff22f9ec8d8e9423214f9666007472 (patch) | |
tree | fa27e0c747676519cb87ff8448bfed62fce5009d /libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvPacket.c | |
parent | f28308bd99381ef5f1e178e2e1f870f245e35873 (diff) | |
parent | d18ae43123fcd7604d1c36a1ec8450dbe6071824 (diff) |
Merge "Initial commit: ccnxlibs." into ccnxlibs/master
Diffstat (limited to 'libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvPacket.c')
-rw-r--r-- | libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvPacket.c | 447 |
1 files changed, 447 insertions, 0 deletions
diff --git a/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvPacket.c b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvPacket.c new file mode 100644 index 00000000..2dfdfcb3 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/test/test_ccnxCodec_TlvPacket.c @@ -0,0 +1,447 @@ +/* + * 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. + */ + +/** + * Does not do detailed tests of the decode -- those are tested in the individual schema_vX unit tests. + * These tests make sure that we (a) get a result when we expect to get a results, and (b) will spot-check + * the result, such as looking at the Name. + * + */ + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. + +#include <config.h> +#include <stdio.h> +#include <fcntl.h> + +#include "../ccnxCodec_TlvPacket.c" +#include <parc/algol/parc_SafeMemory.h> + +#include <LongBow/unit-test.h> + +#include <ccnx/common/codec/ccnxCodec_NetworkBuffer.h> +#include <ccnx/common/validation/ccnxValidation_HmacSha256.h> + +#include <ccnx/common/ccnx_Interest.h> +#include <ccnx/common/ccnx_ContentObject.h> + +#include <ccnx/common/internal/ccnx_InterestDefault.h> + +#include <ccnx/common/codec/schema_v1/testdata/v1_interest_all_fields.h> +#include <ccnx/common/codec/schema_v1/testdata/v1_content_nameA_keyid1_rsasha256.h> +#include <ccnx/common/codec/schema_v1/testdata/v1_interest_bad_message_length.h> + +LONGBOW_TEST_RUNNER(rta_TlvPacket) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(rta_TlvPacket) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(rta_TlvPacket) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, rtaTlvPacket_BufferDecode_V1); + LONGBOW_RUN_TEST_CASE(Global, rtaTlvPacket_BufferDecode_VFF); + + LONGBOW_RUN_TEST_CASE(Global, rtaTlvPacket_IoVecDecode_OneBuffer); + LONGBOW_RUN_TEST_CASE(Global, rtaTlvPacket_IoVecDecode_SeveralBuffer); + + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvPacket_DictionaryEncode_V1); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvPacket_DictionaryEncode_VFF); + + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvPacket_Decode_V1); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvPacket_Decode_VFF); + + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvPacket_EncodeWithSignature); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvPacket_GetPacketLength); + LONGBOW_RUN_TEST_CASE(Global, ccnxCodecTlvPacket_MinimalHeaderLength); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + 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; +} + +LONGBOW_TEST_CASE(Global, rtaTlvPacket_BufferDecode_V1) +{ + PARCBufferComposer *composer = parcBufferComposer_Create(); + PARCBuffer *interestMessage = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), 0, sizeof(v1_interest_all_fields)); + parcBufferComposer_PutBuffer(composer, interestMessage); + parcBuffer_Release(&interestMessage); + + // Append extraneous data to the end of the buffer to make sure the decoder terminates at the end of the CCNx message. + PARCBuffer *padding = parcBuffer_AllocateCString("ThisShouldNeverBeParsed"); + parcBufferComposer_PutBuffer(composer, padding); + parcBuffer_Release(&padding); + PARCBuffer *packetBuffer = parcBufferComposer_CreateBuffer(composer); + parcBufferComposer_Release(&composer); + parcBuffer_Rewind(packetBuffer); + + //PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), 0, sizeof(v1_interest_all_fields)); + CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + bool success = ccnxCodecTlvPacket_BufferDecode(packetBuffer, dict); + assertTrue(success, "Failed to decode good v1 interest"); + + CCNxName *name = ccnxInterest_GetName(dict); + assertNotNull(name, "Did not find a name in the decoded interest"); + + ccnxTlvDictionary_Release(&dict); + parcBuffer_Release(&packetBuffer); +} + +LONGBOW_TEST_CASE(Global, rtaTlvPacket_BufferDecode_VFF) +{ + uint8_t encoded[] = { + 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 + }; + + PARCBuffer *packetBuffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxTlvDictionary *dict = ccnxCodecSchemaV1TlvDictionary_CreateInterest(); + bool success = ccnxCodecTlvPacket_BufferDecode(packetBuffer, dict); + assertFalse(success, "Did not fail on decode of version 255 packet"); + + ccnxTlvDictionary_Release(&dict); + parcBuffer_Release(&packetBuffer); +} + +typedef struct allocator_arg { + size_t maxallocation; +} AllocatorArg; + +static size_t +testAllocator(void *userarg, size_t bytes, void **output) +{ + AllocatorArg *arg = userarg; + if (bytes > arg->maxallocation) { + bytes = arg->maxallocation; + } + + *output = parcMemory_Allocate(bytes); + assertNotNull(*output, "parcMemory_Allocate(%zu) returned NULL", bytes); + if (*output) { + return bytes; + } + return 0; +} + +static void +testDeallocator(void *userarg, void **memory) +{ + parcMemory_Deallocate((void **) memory); +} + +const CCNxCodecNetworkBufferMemoryBlockFunctions TestMemoryBlock = { + .allocator = &testAllocator, + .deallocator = &testDeallocator +}; + + +static void +runIoVecTest(AllocatorArg maxalloc) +{ + CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_Create(&TestMemoryBlock, &maxalloc); + + ccnxCodecNetworkBuffer_PutArray(netbuff, + sizeof(v1_interest_all_fields), + v1_interest_all_fields); + + CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff); + + CCNxTlvDictionary *output = ccnxTlvDictionary_Create(CCNxCodecSchemaV1TlvDictionary_MessageFastArray_END, CCNxCodecSchemaV1TlvDictionary_Lists_END); + + ccnxTlvDictionary_SetMessageType_Interest(output, CCNxTlvDictionary_SchemaVersion_V1); + + bool success = ccnxCodecTlvPacket_IoVecDecode(vec, output); + assertTrue(success, "Failed to decode buffer in iovec format"); + + ccnxTlvDictionary_Release(&output); + ccnxCodecNetworkBufferIoVec_Release(&vec); + ccnxCodecNetworkBuffer_Release(&netbuff); +} + +LONGBOW_TEST_CASE(Global, rtaTlvPacket_IoVecDecode_OneBuffer) +{ + AllocatorArg maxalloc = { .maxallocation = 2048 }; + runIoVecTest(maxalloc); +} + +LONGBOW_TEST_CASE(Global, rtaTlvPacket_IoVecDecode_SeveralBuffer) +{ + // 32 bytes is needed for bookkeeping, so this means we'll have a 32-byte memory block + AllocatorArg maxalloc = { .maxallocation = 64 }; + runIoVecTest(maxalloc); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecTlvPacket_DictionaryEncode_V1) +{ + CCNxName *name = ccnxName_CreateFromCString("ccnx:/Antidisestablishmentarianism"); + CCNxTlvDictionary *message = + ccnxInterest_CreateWithImpl(&CCNxInterestFacadeV1_Implementation, + name, CCNxInterestDefault_LifetimeMilliseconds, NULL, NULL, CCNxInterestDefault_HopLimit); + + CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecTlvPacket_DictionaryEncode(message, NULL); + assertNotNull(iovec, "Got null iovec on a good dictionary"); + + ccnxCodecNetworkBufferIoVec_Release(&iovec); + ccnxTlvDictionary_Release(&message); + ccnxName_Release(&name); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecTlvPacket_DictionaryEncode_VFF) +{ + CCNxTlvDictionary *message = ccnxTlvDictionary_Create(20, 20); + ccnxTlvDictionary_SetMessageType_Interest(message, 0xFF); + CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecTlvPacket_DictionaryEncode(message, NULL); + assertNull(iovec, "Should have gotten null result for schema version 255"); + ccnxTlvDictionary_Release(&message); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecTlvPacket_Decode_V1) +{ + PARCBufferComposer *composer = parcBufferComposer_Create(); + PARCBuffer *interestMessage = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), 0, sizeof(v1_interest_all_fields)); + parcBufferComposer_PutBuffer(composer, interestMessage); + parcBuffer_Release(&interestMessage); + + // Append extraneous data to the end of the buffer to make sure the decoder terminates at the end of the CCNx message. + PARCBuffer *padding = parcBuffer_AllocateCString("ThisShouldNeverBeParsed"); + parcBufferComposer_PutBuffer(composer, padding); + parcBuffer_Release(&padding); + PARCBuffer *packetBuffer = parcBufferComposer_CreateBuffer(composer); + parcBufferComposer_Release(&composer); + parcBuffer_Rewind(packetBuffer); + + CCNxTlvDictionary *dict = ccnxCodecTlvPacket_Decode(packetBuffer); + assertNotNull(dict, "Got null dictionary decoding good packet"); + + ccnxTlvDictionary_Release(&dict); + parcBuffer_Release(&packetBuffer); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecTlvPacket_Decode_VFF) +{ + uint8_t encoded[] = { + 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 + }; + + PARCBuffer *packetBuffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + + CCNxTlvDictionary *dict = ccnxCodecTlvPacket_Decode(packetBuffer); + assertNull(dict, "Got non-null dictionary decoding version 255 packet"); + parcBuffer_Release(&packetBuffer); +} + + +LONGBOW_TEST_CASE(Global, ccnxCodecTlvPacket_EncodeWithSignature) +{ + CCNxName *name = ccnxName_CreateFromCString("ccnx:/foo/bar"); + PARCBuffer *payload = parcBuffer_WrapCString("payload"); + CCNxContentObject *obj = ccnxContentObject_CreateWithNameAndPayload(name, payload); + ccnxName_Release(&name); + parcBuffer_Release(&payload); + + PARCBuffer *secretKey = parcBuffer_WrapCString("abcdefghijklmnopqrstuvwxyx"); + PARCSigner *signer = ccnxValidationHmacSha256_CreateSigner(secretKey); + + // should really scrub the memory + parcBuffer_Release(&secretKey); + + // this was breaking the signature + PARCKeyStore *keyStore = parcSigner_GetKeyStore(signer); + const PARCCryptoHash *secretHash = parcKeyStore_GetVerifierKeyDigest(keyStore); + const PARCBuffer *keyid = parcCryptoHash_GetDigest(secretHash); + ccnxValidationHmacSha256_Set(obj, keyid); + parcCryptoHash_Release((PARCCryptoHash **) &secretHash); + + CCNxCodecNetworkBufferIoVec *iovec = ccnxCodecTlvPacket_DictionaryEncode(obj, signer); + + ccnxCodecNetworkBufferIoVec_Display(iovec, 0); + + int fd = open("/dev/null", O_WRONLY); + assertTrue(fd != -1, "Error opening /dev/null"); + + ssize_t written = writev(fd, ccnxCodecNetworkBufferIoVec_GetArray(iovec), ccnxCodecNetworkBufferIoVec_GetCount(iovec)); + assertTrue(written != -1, "Error writting to /dev/null"); + close(fd); + + ccnxCodecNetworkBufferIoVec_Release(&iovec); + parcSigner_Release(&signer); + ccnxContentObject_Release(&obj); +} + +static uint8_t testDataV1_Interest_AllFields[] = { + 0x01, 0x00, 0x00, 100, // ver = 1, type = interest, length = 100 + 0x20, 0x00, 0x11, 14, // HopLimit = 32, reserved = 0, flags = 0x11, header length = 14 + // ------------------------ + 0x00, 0x01, 0x00, 2, // Interest Lifetime (2 bytes) + 0xEA, 0xEB, + // ------------------------ + 0x00, 0x01, 0x00, 82, // type = interest, length = 82 + // ------------------------ + 0x00, 0x00, 0x00, 8, // type = name, length = 8 + 0x00, 0x02, 0x00, 4, // type = binary, length = 4 + 'c', 'o', 'o', 'l', // "cool" + // ------------------------ + 0x00, 0x02, 0x00, 16, // type = keyid restriction, length = 16 + 0xa0, 0xa1, 0xa2, 0xa3, + 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, + 0xac, 0xad, 0xae, 0xaf, + // ------------------------ + 0x00, 0x03, 0x00, 32, // type = hash restriction, length = 32 + 0xb0, 0xb1, 0xb2, 0xb3, + 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, + 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, + 0xcc, 0xcd, 0xce, 0xcf, + // ------------------------ + 0x00, 0x04, 0x00, 1, // Internest payload method (1 byte) + 0x00, + // ------------------------ + 0x00, 0x01, 0x00, 5, // type = payload, length = 5 + 0xD0, 0xD1, 0xD2, 0xD3, + 0xD4, +}; + +LONGBOW_TEST_CASE(Global, ccnxCodecTlvPacket_GetPacketLength) +{ + PARCBuffer *packet = parcBuffer_Wrap(testDataV1_Interest_AllFields, sizeof(testDataV1_Interest_AllFields), 0, sizeof(testDataV1_Interest_AllFields)); + size_t packetLength = ccnxCodecTlvPacket_GetPacketLength(packet); + assertTrue(packetLength == sizeof(testDataV1_Interest_AllFields), "Wrong total message length, expected %zu got %zu", sizeof(testDataV1_Interest_AllFields), packetLength); + parcBuffer_Release(&packet); +} + +LONGBOW_TEST_CASE(Global, ccnxCodecTlvPacket_MinimalHeaderLength) +{ + assertTrue(ccnxCodecTlvPacket_MinimalHeaderLength() > 0, "ccnxCodecTlvPacket_MinimalHeaderLength failed"); +} + +// ================================================================= + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Global, _decodeV1_Interest); + LONGBOW_RUN_TEST_CASE(Global, _decodeV1_ContentObject); + LONGBOW_RUN_TEST_CASE(Global, _decodeV1_Control); + LONGBOW_RUN_TEST_CASE(Global, _decodeV1_Unknown); + LONGBOW_RUN_TEST_CASE(Global, _decodeV1_Error); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, _decodeV1_Interest) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_all_fields, sizeof(v1_interest_all_fields), 0, sizeof(v1_interest_all_fields)); + CCNxTlvDictionary *dict = _decodeV1(packetBuffer); + assertNotNull(dict, "Error decoding good packet"); + + CCNxName *name = ccnxInterest_GetName(dict); + assertNotNull(name, "Null name in decoded Interest"); + + ccnxTlvDictionary_Release(&dict); + parcBuffer_Release(&packetBuffer); +} + +LONGBOW_TEST_CASE(Global, _decodeV1_ContentObject) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_content_nameA_keyid1_rsasha256, sizeof(v1_content_nameA_keyid1_rsasha256), 0, sizeof(v1_content_nameA_keyid1_rsasha256)); + CCNxTlvDictionary *dict = _decodeV1(packetBuffer); + assertNotNull(dict, "Error decoding good packet"); + + CCNxName *name = ccnxContentObject_GetName(dict); + assertNotNull(name, "Null name in decoded Interest"); + + ccnxTlvDictionary_Release(&dict); + parcBuffer_Release(&packetBuffer); +} + +LONGBOW_TEST_CASE(Global, _decodeV1_Control) +{ + testUnimplemented("V1 control not implemented yet"); +} + +LONGBOW_TEST_CASE(Global, _decodeV1_Unknown) +{ + uint8_t encoded[] = { + 0x01, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 + }; + + PARCBuffer *packetBuffer = parcBuffer_Wrap(encoded, sizeof(encoded), 0, sizeof(encoded)); + CCNxTlvDictionary *dict = _decodeV1(packetBuffer); + assertNull(dict, "Should have gotten NULL dictionary from unknown packet type"); + + parcBuffer_Release(&packetBuffer); +} + +LONGBOW_TEST_CASE(Global, _decodeV1_Error) +{ + PARCBuffer *packetBuffer = parcBuffer_Wrap(v1_interest_bad_message_length, sizeof(v1_interest_bad_message_length), 0, sizeof(v1_interest_bad_message_length)); + CCNxTlvDictionary *dict = _decodeV1(packetBuffer); + assertNull(dict, "Should have gotten NULL dictionary from unknown packet type"); + + parcBuffer_Release(&packetBuffer); +} + +// ================================================================= + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(rta_TlvPacket); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} |