diff options
Diffstat (limited to 'libccnx-transport-rta/ccnx/api/control/test')
26 files changed, 6050 insertions, 0 deletions
diff --git a/libccnx-transport-rta/ccnx/api/control/test/.gitignore b/libccnx-transport-rta/ccnx/api/control/test/.gitignore new file mode 100644 index 00000000..f6caadab --- /dev/null +++ b/libccnx-transport-rta/ccnx/api/control/test/.gitignore @@ -0,0 +1,24 @@ +test_controlPlaneInterface +test_cpi_Acks +test_cpi_Address +test_cpi_AddressList +test_cpi_CancelFlow +test_cpi_Connection +test_cpi_ControlFacade +test_cpi_ControlMessage +test_cpi_ConnectionEthernet +test_cpi_ConnectionList +test_cpi_Forwarding +test_cpi_Interface +test_cpi_InterfaceEthernet +test_cpi_InterfaceGeneric +test_cpi_InterfaceIPTunnel +test_cpi_InterfaceIPTunnelList +test_cpi_InterfaceSet +test_cpi_InterfaceTypes +test_cpi_Listener +test_cpi_ManageLinks +test_cpi_NameRouteType +test_cpi_Registration +test_cpi_RouteEntry +test_cpi_RouteEntryList diff --git a/libccnx-transport-rta/ccnx/api/control/test/CMakeLists.txt b/libccnx-transport-rta/ccnx/api/control/test/CMakeLists.txt new file mode 100644 index 00000000..a573213c --- /dev/null +++ b/libccnx-transport-rta/ccnx/api/control/test/CMakeLists.txt @@ -0,0 +1,36 @@ +# Enable gcov output for the tests +add_definitions(--coverage) +set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage") + +set(TestsExpectedToPass + test_cpi_Acks + test_cpi_Address + test_cpi_AddressList + test_cpi_CancelFlow + test_cpi_Connection + test_cpi_ConnectionEthernet + test_cpi_ConnectionList + test_cpi_ControlMessage + test_cpi_ControlFacade + test_cpi_Interface + test_cpi_InterfaceSet + test_cpi_InterfaceTypes + test_cpi_InterfaceGeneric + test_cpi_InterfaceEthernet + test_cpi_InterfaceIPTunnel + test_cpi_InterfaceIPTunnelList + test_cpi_Forwarding + test_cpi_Listener + test_cpi_ManageLinks + test_cpi_NameRouteType + test_cpi_Registration + test_cpi_RouteEntry + test_cpi_RouteEntryList + test_controlPlaneInterface +) + + +foreach(test ${TestsExpectedToPass}) + AddTest(${test}) +endforeach() + diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_controlPlaneInterface.c b/libccnx-transport-rta/ccnx/api/control/test/test_controlPlaneInterface.c new file mode 100644 index 00000000..8dfbb362 --- /dev/null +++ b/libccnx-transport-rta/ccnx/api/control/test/test_controlPlaneInterface.c @@ -0,0 +1,287 @@ +/* + * 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 "../controlPlaneInterface.c" + +#include <LongBow/unit-test.h> + +#include <ccnx/api/control/cpi_ControlFacade.h> + +#include <parc/algol/parc_Memory.h> +#include <parc/algol/parc_SafeMemory.h> + +LONGBOW_TEST_RUNNER(controlPlaneInterface) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(controlPlaneInterface) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(controlPlaneInterface) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, cpi_CreateRequest); + LONGBOW_RUN_TEST_CASE(Global, cpi_CreateResponse); + LONGBOW_RUN_TEST_CASE(Global, cpi_ParseRequest); + + LONGBOW_RUN_TEST_CASE(Global, cpi_PauseInput); + + LONGBOW_RUN_TEST_CASE(Global, controlPlaneInterface_PauseInput); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + 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, cpi_CreateRequest) +{ + const char key_looney[] = "looney"; + + PARCJSON *operation = parcJSON_Create(); + parcJSON_AddString(operation, "bugs", "bunny"); + + PARCJSON *request = cpi_CreateRequest(key_looney, operation); + parcJSON_Release(&operation); + + PARCJSONValue *value = parcJSON_GetValueByName(request, cpiRequest); + assertNotNull(value, + "JSON key not found %s: %s", + cpiRequest, + parcJSON_ToString(request)); + assertTrue(parcJSONValue_IsJSON(value), + "Key %s wrong type: %s", + cpiRequest, + parcJSON_ToString(request)); + PARCJSON *test_request_key = parcJSONValue_GetJSON(value); + + value = parcJSON_GetValueByName(test_request_key, cpiSeqnum); + assertNotNull(value, + "JSON key not found %s: %s", + cpiSeqnum, + parcJSON_ToString(request)); + assertTrue(parcJSONValue_IsNumber(value), + "Key %s wrong type: %s", + cpiSeqnum, + parcJSON_ToString(request)); + + value = parcJSON_GetValueByName(test_request_key, key_looney); + assertNotNull(value, + "JSON key not found %s: %s", + key_looney, + parcJSON_ToString(request)); + assertTrue(parcJSONValue_IsJSON(value), + "Key %s wrong type: %s", + key_looney, + parcJSON_ToString(request)); + + parcJSON_Release(&request); +} + +LONGBOW_TEST_CASE(Global, cpi_CreateResponse) +{ + const char key_looney[] = "looney"; + + PARCJSON *requestOperation = parcJSON_Create(); + parcJSON_AddString(requestOperation, "bugs", "bunny"); + + PARCJSON *requestJson = cpi_CreateRequest(key_looney, requestOperation); + parcJSON_Release(&requestOperation); + + // + // we should now have an object that looks, like + // { "CPI_REQUEST": { "SEQUENCE":1, "looney":{"bugs":"bunny"} } } + // + // The sequence number might not be exactly 1, depending on how the + // unit tests are ordered and forked. + // + char *expectedStr1 = "{\"CPI_REQUEST\":{\"SEQUENCE\":"; + char *expectedStr2 = ",\"looney\":{\"bugs\":\"bunny\"}}}"; + char *jsonStr = parcJSON_ToCompactString(requestJson); + size_t len = strlen(expectedStr1); + assertTrue(strncmp(jsonStr, expectedStr1, len) == 0, "Expect JSON strings to be the same"); + assertTrue(strncmp(jsonStr + len + 1, expectedStr2, strlen(expectedStr2)) == 0, "Expect JSON strings to be the same"); + parcMemory_Deallocate(&jsonStr); + + CCNxControl *request = ccnxControl_CreateCPIRequest(requestJson); + + PARCJSON *responseOperation = parcJSON_Create(); + parcJSON_AddString(responseOperation, "donald", "duck"); + + CCNxControl *response = cpi_CreateResponse(request, responseOperation); + parcJSON_Release(&responseOperation); + + PARCJSON *responseJson = ccnxControl_GetJson(response); + // + // we should now have an object that looks, like + // { "CPI_RESPONSE": { "SEQUENCE":1, "looney":{"donald":"duck"} } } + // + // The sequence number might not be exactly 1, depending on how the + // unit tests are ordered and forked. It should be the same as the request. + // + expectedStr1 = "{\"CPI_RESPONSE\":{\"SEQUENCE\":"; + expectedStr2 = ",\"looney\":{\"donald\":\"duck\"}}}"; + jsonStr = parcJSON_ToCompactString(responseJson); + len = strlen(expectedStr1); + assertTrue(strncmp(jsonStr, expectedStr1, len) == 0, "Expect JSON strings to be the same"); + assertTrue(strncmp(jsonStr + len + 1, expectedStr2, strlen(expectedStr2)) == 0, "Expect JSON strings to be the same"); + parcMemory_Deallocate(&jsonStr); + + PARCJSONValue *value = parcJSON_GetValueByName(responseJson, cpiResponse); + assertNotNull(value, + "JSON key not found %s: %s", + cpiResponse, + parcJSON_ToString(responseJson)); + assertTrue(parcJSONValue_IsJSON(value), + "Key %s wrong type: %s", + cpiResponse, + parcJSON_ToString(responseJson)); + PARCJSON *test_response_key = parcJSONValue_GetJSON(value); + + value = parcJSON_GetValueByName(test_response_key, cpiSeqnum); + assertNotNull(value, + "JSON key not found %s: %s", + cpiSeqnum, + parcJSON_ToString(test_response_key)); + assertTrue(parcJSONValue_IsNumber(value), + "Key %s wrong type: %s", + cpiSeqnum, + parcJSON_ToString(responseJson)); + + value = parcJSON_GetValueByName(test_response_key, key_looney); + assertNotNull(value, + "JSON key not found %s: %s", + key_looney, + parcJSON_ToString(responseJson)); + assertTrue(parcJSONValue_IsJSON(value), + "Key %s wrong type: %s", + key_looney, + parcJSON_ToString(responseJson)); + + ccnxControl_Release(&response); + ccnxControl_Release(&request); + + parcJSON_Release(&requestJson); +} + +LONGBOW_TEST_CASE(Global, cpi_ParseRequest) +{ + char key_looney[] = "looney"; + const char value_looney[] = "{\"bugs\":\"bunny\"}"; + + PARCJSON *operation = parcJSON_Create(); + parcJSON_AddString(operation, "bugs", "bunny"); + + PARCJSON *request = cpi_CreateRequest(key_looney, operation); + parcJSON_Release(&operation); + + // + // we should now have an object that looks, like + // { "CPI_REQUEST": { "SEQUENCE":1, "looney":{"bugs":"bunny"} } } + // + // The sequence number might not be exactly 1, depending on how the + // unit tests are ordered and forked. + // + + PARCJSONPair *parsedOpPair = cpi_ParseRequest(request); + assertNotNull(parsedOpPair, "Got null parsed json from %s", parcJSON_ToString(request)); + + PARCBuffer *key = parcJSONPair_GetName(parsedOpPair); + PARCBuffer *test_key = parcBuffer_WrapCString(key_looney); + assertTrue(parcBuffer_Equals(key, test_key), + "Key name of parsed wrong, expected %s got %s in %s", + key_looney, + parcBuffer_ToString(key), + parcJSONPair_ToString(parsedOpPair)); + parcBuffer_Release(&test_key); + + operation = parcJSONValue_GetJSON(parcJSONPair_GetValue(parsedOpPair)); + char *test_looney = parcJSON_ToCompactString(operation); + assertTrue(strcmp(value_looney, test_looney) == 0, + "Inner values did not match, expected %s got %s in %s", + value_looney, + test_looney, + parcJSONPair_ToString(parsedOpPair)); + parcMemory_Deallocate((void **) &test_looney); + + parcJSON_Release(&request); +} + +LONGBOW_TEST_CASE(Global, controlPlaneInterface_PauseInput) +{ + CCNxControl *message = ccnxControl_CreatePauseInputRequest(); + + assertTrue(ccnxControlFacade_IsCPI(message), "Expected ccnxControlMessage_IsCPI to be true"); + + PARCJSON *json = ccnxControlFacade_GetJson(message); + assertTrue(ccnxControl_IsCPI(message), "Expected a CPI control message"); + assertTrue(cpi_getCPIOperation2(json) == CPI_PAUSE, + "Expected opertaion %d got %d", CPI_PAUSE, cpi_getCPIOperation2(json)); + + ccnxControl_Release(&message); +} + +LONGBOW_TEST_CASE(Global, cpi_PauseInput) +{ + PARCJSON *pauseRequest = cpi_CreatePauseInputRequest(); + CCNxControl *request = ccnxControl_CreateCPIRequest(pauseRequest); + parcJSON_Release(&pauseRequest); + + assertTrue(ccnxControl_IsCPI(request), "Is not a CPI message!"); + assertTrue(cpi_GetMessageType(request) == CPI_REQUEST, + "Got wrong message type, expected %d got %d", + CPI_REQUEST, + cpi_GetMessageType(request)); + + assertTrue(cpi_GetMessageOperation(request) == CPI_PAUSE, + "got wrong operation, expected %d got %d", + CPI_PAUSE, + cpi_GetMessageOperation(request)); + + ccnxControl_Release(&request); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(controlPlaneInterface); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Acks.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Acks.c new file mode 100644 index 00000000..ecdcf40f --- /dev/null +++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Acks.c @@ -0,0 +1,119 @@ +/* + * 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 "../cpi_Acks.c" +#include <LongBow/unit-test.h> + +#include <parc/algol/parc_SafeMemory.h> + + +LONGBOW_TEST_RUNNER(cpi_Acks) +{ + // 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); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(cpi_Acks) +{ + 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(cpi_Acks) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, cpiAck_CreateAck); + LONGBOW_RUN_TEST_CASE(Global, cpiAck_CreateNack); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + 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, cpiAck_CreateAck) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar"); + CPIRouteEntry *route = cpiRouteEntry_CreateRouteToSelf(name); + PARCJSON *request = cpiForwarding_CreateAddRouteRequest(route); + + PARCJSON *actual = cpiAcks_CreateAck(request); + + assertTrue(cpiAcks_IsAck(actual), "Expected cpiAcks_IsAck to return true."); + + parcJSON_Release(&actual); + parcJSON_Release(&request); + cpiRouteEntry_Destroy(&route); + ccnxName_Release(&name); +} + +LONGBOW_TEST_CASE(Global, cpiAck_CreateNack) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar"); + CPIRouteEntry *route = cpiRouteEntry_CreateRouteToSelf(name); + PARCJSON *request = cpiForwarding_CreateAddRouteRequest(route); + + PARCJSON *actual = cpiAcks_CreateNack(request); + + assertFalse(cpiAcks_IsAck(actual), "Expected cpiAcks_IsAck to return false."); + + parcJSON_Release(&actual); + parcJSON_Release(&request); + cpiRouteEntry_Destroy(&route); + ccnxName_Release(&name); +} + +LONGBOW_TEST_FIXTURE(Local) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_Acks); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Address.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Address.c new file mode 100644 index 00000000..fbb63f7d --- /dev/null +++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Address.c @@ -0,0 +1,550 @@ +/* + * 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. + */ + +/** + * Each type test (inet, inet6, etc.) should test: + * - CreateFromX + * - GetX + * - GetType = X + * - Y = cpiAddress_CreateFromJson( cpiAddress_ToJson(X) ) == X + * - Equals(Y, X) + * - Equals(Copy(X), X) + */ + +// for inet_pton +#include <config.h> +#include <arpa/inet.h> +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../cpi_Address.c" + +LONGBOW_TEST_RUNNER(cpi_Address) +{ + // 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(cpi_Address) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(cpi_Address) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, cpiAddress_Copy); + LONGBOW_RUN_TEST_CASE(Global, cpiAddress_Equals_ReallyEqual); + LONGBOW_RUN_TEST_CASE(Global, cpiAddress_Equals_SamePointer); + LONGBOW_RUN_TEST_CASE(Global, cpiAddress_Equals_NotEqual); + LONGBOW_RUN_TEST_CASE(Global, cpiAddress_CreateFromInet); + LONGBOW_RUN_TEST_CASE(Global, cpiAddress_CreateFromInet6); + LONGBOW_RUN_TEST_CASE(Global, cpiAddress_CreateFromInterface); + LONGBOW_RUN_TEST_CASE(Global, cpiAddress_CreateFromLink); + LONGBOW_RUN_TEST_CASE(Global, cpiAddress_CreateFromUnix); + + LONGBOW_RUN_TEST_CASE(Global, cpiAddress_ToString_INET); + LONGBOW_RUN_TEST_CASE(Global, cpiAddress_ToString_INET6); + LONGBOW_RUN_TEST_CASE(Global, cpiAddress_ToString_LINK); + LONGBOW_RUN_TEST_CASE(Global, cpiAddress_ToString_IFACE); + LONGBOW_RUN_TEST_CASE(Global, cpiAddress_ToString_UNIX); + + LONGBOW_RUN_TEST_CASE(Global, cpiAddress_BuildString); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + 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, cpiAddress_Copy) +{ + CPIAddress *a = cpiAddress_CreateFromInterface(1); + CPIAddress *b = cpiAddress_Copy(a); + + assertTrue(cpiAddress_Equals(a, b), "Copy did not compare as equal: %s and %s", cpiAddress_ToString(a), cpiAddress_ToString(b)); + + cpiAddress_Destroy(&a); + cpiAddress_Destroy(&b); +} + +LONGBOW_TEST_CASE(Global, cpiAddress_Equals_ReallyEqual) +{ + struct sockaddr_in addr_in; + memset(&addr_in, 0, sizeof(struct sockaddr_in)); + + addr_in.sin_addr.s_addr = 0x01020304; + addr_in.sin_family = AF_INET; + addr_in.sin_port = 0x0A0B; + + CPIAddress *a = cpiAddress_CreateFromInet(&addr_in); + CPIAddress *b = cpiAddress_CreateFromInet(&addr_in); + + assertTrue(cpiAddress_Equals(a, b), "Equals did not compare two equal addresses: %s and %s", cpiAddress_ToString(a), cpiAddress_ToString(b)); + + cpiAddress_Destroy(&a); + cpiAddress_Destroy(&b); +} + +LONGBOW_TEST_CASE(Global, cpiAddress_Equals_SamePointer) +{ + struct sockaddr_in addr_in; + memset(&addr_in, 0, sizeof(struct sockaddr_in)); + + addr_in.sin_addr.s_addr = 0x01020304; + addr_in.sin_family = AF_INET; + addr_in.sin_port = 0x0A0B; + + CPIAddress *a = cpiAddress_CreateFromInet(&addr_in); + + assertTrue(cpiAddress_Equals(a, a), "Equals did not compare two equal addresses: %s and %s", cpiAddress_ToString(a), cpiAddress_ToString(a)); + + cpiAddress_Destroy(&a); +} + +LONGBOW_TEST_CASE(Global, cpiAddress_Equals_NotEqual) +{ + struct sockaddr_in addr_in; + memset(&addr_in, 0, sizeof(struct sockaddr_in)); + + addr_in.sin_addr.s_addr = 0x01020304; + addr_in.sin_family = AF_INET; + addr_in.sin_port = 0x0A0B; + + CPIAddress *a = cpiAddress_CreateFromInet(&addr_in); + CPIAddress *b = cpiAddress_CreateFromInterface(1); + + assertFalse(cpiAddress_Equals(a, b), "Equals failed on different addresses: %s and %s", cpiAddress_ToString(a), cpiAddress_ToString(b)); + + cpiAddress_Destroy(&a); + cpiAddress_Destroy(&b); +} + + +LONGBOW_TEST_CASE(Global, cpiAddress_CreateFromInet) +{ + struct sockaddr_in addr_in; + struct sockaddr_in addr_test; + memset(&addr_in, 0, sizeof(struct sockaddr_in)); + + addr_in.sin_addr.s_addr = 0x01020304; + addr_in.sin_family = AF_INET; + addr_in.sin_port = 0x0A0B; + + CPIAddress *address = cpiAddress_CreateFromInet(&addr_in); + + bool success = cpiAddress_GetInet(address, &addr_test); + assertTrue(success, "Got false converting back address"); + + assertTrue(memcmp(&addr_in, &addr_test, sizeof(struct sockaddr_in)) == 0, "Got mismatch addressed"); + + assertTrue(cpiAddress_GetType(address) == cpiAddressType_INET, + "Got wrong address type, expected %d, got %d", cpiAddressType_INET, cpiAddress_GetType(address)); + + PARCJSON *json = cpiAddress_ToJson(address); + CPIAddress *fromjson = cpiAddress_CreateFromJson(json); + + assertTrue(cpiAddress_GetType(address) == cpiAddress_GetType(fromjson), "fromjson type does not equal known"); + assertTrue(parcBuffer_Equals(address->blob, fromjson->blob), "fromjson blob does not equal known address"); + assertTrue(cpiAddress_Equals(address, fromjson), "cpiAddress_Equals broken for INET type"); + + // This test does too much. Case 1032 + CPIAddress *copy = cpiAddress_Copy(address); + assertTrue(cpiAddress_Equals(copy, address), "Copy and address not equal for INET"); + + cpiAddress_Destroy(©); + cpiAddress_Destroy(&fromjson); + + parcJSON_Release(&json); + + cpiAddress_Destroy(&address); + return; +} + +LONGBOW_TEST_CASE(Global, cpiAddress_CreateFromInet6) +{ + struct sockaddr_in6 addr_in6; + memset(&addr_in6, 0, sizeof(struct sockaddr_in6)); + + inet_pton(AF_INET6, "2001:720:1500:1::a100", &(addr_in6.sin6_addr)); + addr_in6.sin6_family = AF_INET6; + addr_in6.sin6_port = 0x0A0B; + addr_in6.sin6_flowinfo = 0x01020304; + + CPIAddress *address = cpiAddress_CreateFromInet6(&addr_in6); + + struct sockaddr_in6 addr_test; + bool success = cpiAddress_GetInet6(address, &addr_test); + assertTrue(success, "Got false converting back address"); + + assertTrue(memcmp(&addr_in6, &addr_test, sizeof(struct sockaddr_in6)) == 0, "Got mismatch addressed"); + + assertTrue(cpiAddress_GetType(address) == cpiAddressType_INET6, + "Got wrong address type, expected %d, got %d", cpiAddressType_INET6, cpiAddress_GetType(address)); + + PARCJSON *json = cpiAddress_ToJson(address); + CPIAddress *fromjson = cpiAddress_CreateFromJson(json); + + assertTrue(parcBuffer_Equals(address->blob, fromjson->blob), "fromjson blob does not equal known address"); + assertTrue(cpiAddress_Equals(address, fromjson), "cpiAddress_Equals broken for INET6 type"); + + CPIAddress *copy = cpiAddress_Copy(address); + assertTrue(cpiAddress_Equals(copy, address), "Copy and address not equal for INET6"); + + parcJSON_Release(&json); + cpiAddress_Destroy(&address); + cpiAddress_Destroy(©); + cpiAddress_Destroy(&fromjson); +} + +LONGBOW_TEST_CASE(Global, cpiAddress_CreateFromUnix) +{ + struct sockaddr_un addr_un; + struct sockaddr_un addr_test; + memset(&addr_un, 0, sizeof(struct sockaddr_un)); + char path[] = "/Hello/Cruel/World"; + strcpy(addr_un.sun_path, path); + addr_un.sun_family = AF_UNIX; + + CPIAddress *address = cpiAddress_CreateFromUnix(&addr_un); + + bool success = cpiAddress_GetUnix(address, &addr_test); + assertTrue(success, "Got false converting back address"); + + assertTrue(memcmp(&addr_un, &addr_test, sizeof(struct sockaddr_un)) == 0, "Got mismatch addressed"); + + assertTrue(cpiAddress_GetType(address) == cpiAddressType_UNIX, + "Got wrong address type, expected %d, got %d", cpiAddressType_UNIX, cpiAddress_GetType(address)); + + PARCJSON *json = cpiAddress_ToJson(address); + CPIAddress *fromjson = cpiAddress_CreateFromJson(json); + + assertTrue(parcBuffer_Equals(address->blob, fromjson->blob), "fromjson blob does not equal known address"); + assertTrue(cpiAddress_Equals(address, fromjson), "cpiAddress_Equals broken for UNIX type"); + + CPIAddress *copy = cpiAddress_Copy(address); + assertTrue(cpiAddress_Equals(copy, address), "Copy and address not equal for UNIX"); + + parcJSON_Release(&json); + cpiAddress_Destroy(&address); + cpiAddress_Destroy(©); + cpiAddress_Destroy(&fromjson); +} + +LONGBOW_TEST_CASE(Global, cpiAddress_CreateFromInterface) +{ + uint32_t ifidx = 0x01020304; + uint32_t test; + + CPIAddress *address = cpiAddress_CreateFromInterface(ifidx); + + bool success = cpiAddress_GetInterfaceIndex(address, &test); + assertTrue(success, "Got false converting back address"); + + assertTrue(ifidx == test, "Got mismatch addressed"); + + assertTrue(cpiAddress_GetType(address) == cpiAddressType_IFACE, + "Got wrong address type, expected %d, got %d", cpiAddressType_IFACE, cpiAddress_GetType(address)); + + PARCJSON *json = cpiAddress_ToJson(address); + CPIAddress *fromjson = cpiAddress_CreateFromJson(json); + + assertTrue(parcBuffer_Equals(address->blob, fromjson->blob), "fromjson blob does not equal known address"); + assertTrue(cpiAddress_Equals(address, fromjson), "cpiAddress_Equals broken for IFACE type"); + + CPIAddress *copy = cpiAddress_Copy(address); + assertTrue(cpiAddress_Equals(copy, address), "Copy and address not equal for IFACE"); + + parcJSON_Release(&json); + cpiAddress_Destroy(&address); + cpiAddress_Destroy(©); + cpiAddress_Destroy(&fromjson); +} + +LONGBOW_TEST_CASE(Global, cpiAddress_CreateFromLink) +{ + uint8_t mac[] = { 0x01, 0x02, 0x03, 0x04, 0xFF, 0x8F }; + PARCBuffer *macbuffer = parcBuffer_Flip(parcBuffer_CreateFromArray(mac, sizeof(mac))); + + CPIAddress *address = cpiAddress_CreateFromLink(mac, sizeof(mac)); + + // Do not release test, it is the same reference as address->blob + PARCBuffer *test = cpiAddress_GetLinkAddress(address); + assertNotNull(test, "Got null link address buffer"); + assertTrue(parcBuffer_Equals(test, address->blob), "Returned buffer from cpiAddress_GetLinkAddress not equal to address"); + + assertTrue(cpiAddress_GetType(address) == cpiAddressType_LINK, + "Got wrong address type, expected %d, got %d", cpiAddressType_LINK, cpiAddress_GetType(address)); + + PARCJSON *json = cpiAddress_ToJson(address); + CPIAddress *fromjson = cpiAddress_CreateFromJson(json); + + assertTrue(cpiAddress_GetType(address) == cpiAddress_GetType(fromjson), + "fromjson type does not equal known"); + assertTrue(parcBuffer_Equals(address->blob, fromjson->blob), + "fromjson blob does not equal known address"); + assertTrue(cpiAddress_Equals(address, fromjson), + "cpiAddress_Equals broken for LINK type"); + + CPIAddress *copy = cpiAddress_Copy(address); + assertTrue(cpiAddress_Equals(copy, address), + "Copy and address not equal for LINK"); + + parcJSON_Release(&json); + cpiAddress_Destroy(&address); + cpiAddress_Destroy(©); + cpiAddress_Destroy(&fromjson); + parcBuffer_Release(&macbuffer); +} + +LONGBOW_TEST_CASE(Global, cpiAddress_ToString_INET) +{ + struct sockaddr_in *addr_in = parcNetwork_SockInet4Address("1.2.3.4", 12345); + + char expected[] = "inet4://1.2.3.4:12345"; + + CPIAddress *cpiaddr = cpiAddress_CreateFromInet(addr_in); + + char *actual = cpiAddress_ToString(cpiaddr); + + assertTrue(strcmp(actual, expected) == 0, "Bad string, expected '%s' got '%s'", expected, actual); + + parcMemory_Deallocate((void **) &actual); + cpiAddress_Destroy(&cpiaddr); + parcMemory_Deallocate((void **) &addr_in); +} + +LONGBOW_TEST_CASE(Global, cpiAddress_ToString_UNIX) +{ + struct sockaddr_un addr_un; + char path[] = "/Hello/Cruel/World"; + memset(&addr_un, 0, sizeof(struct sockaddr_un)); + strcpy(addr_un.sun_path, path); + addr_un.sun_family = AF_UNIX; + + char truth_str[] = "{ .type=UNIX, .data={ .path=/Hello/Cruel/World, .len=18 } }"; + + CPIAddress *cpiaddr = cpiAddress_CreateFromUnix(&addr_un); + + char *output = cpiAddress_ToString(cpiaddr); + + assertTrue(strcmp(output, truth_str) == 0, "Bad string, expected %s got %s", truth_str, output); + + parcMemory_Deallocate((void **) &output); + cpiAddress_Destroy(&cpiaddr); +} + +LONGBOW_TEST_CASE(Global, cpiAddress_ToString_INET6) +{ + struct sockaddr_in6 addr_in6; + memset(&addr_in6, 0, sizeof(struct sockaddr_in6)); + + inet_pton(AF_INET6, "2001:720:1500:1::a100", &(addr_in6.sin6_addr)); + addr_in6.sin6_family = AF_INET6; + addr_in6.sin6_port = htons(43215); + + char *expected = "inet6://[2001:720:1500:1::a100%0]:43215"; + + CPIAddress *cpiaddr = cpiAddress_CreateFromInet6(&addr_in6); + char *actual = cpiAddress_ToString(cpiaddr); + + assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual); + + parcMemory_Deallocate((void **) &actual); + cpiAddress_Destroy(&cpiaddr); +} + +LONGBOW_TEST_CASE(Global, cpiAddress_ToString_LINK) +{ + uint8_t addr[6] = { 0x01, 0x02, 0x03, 0xF4, 0xF5, 0xF6 }; + + char truth_str[] = "link://01-02-03-f4-f5-f6"; + + CPIAddress *cpiaddr = cpiAddress_CreateFromLink(addr, sizeof(addr)); + char *output = cpiAddress_ToString(cpiaddr); + + assertTrue(strcmp(output, truth_str) == 0, + "Bad string, expected %s got %s", truth_str, output); + + parcMemory_Deallocate((void **) &output); + cpiAddress_Destroy(&cpiaddr); +} + +LONGBOW_TEST_CASE(Global, cpiAddress_ToString_IFACE) +{ + char truth_str[] = "{ .type=IFACE, .data={ .ifidx=55 } }"; + + CPIAddress *cpiaddr = cpiAddress_CreateFromInterface(55); + char *output = cpiAddress_ToString(cpiaddr); + + assertTrue(strcmp(output, truth_str) == 0, "Bad string, expected %s got %s", truth_str, output); + + parcMemory_Deallocate((void **) &output); + cpiAddress_Destroy(&cpiaddr); +} + +LONGBOW_TEST_CASE(Global, cpiAddress_BuildString) +{ + CPIAddress *address = cpiAddress_CreateFromInterface(1); + uint32_t beforeBalance = parcMemory_Outstanding(); + PARCBufferComposer *composer = cpiAddress_BuildString(address, parcBufferComposer_Create()); + parcBufferComposer_Release(&composer); + uint32_t afterBalance = parcMemory_Outstanding(); + + cpiAddress_Destroy(&address); + assertTrue(beforeBalance == afterBalance, "Memory leak off by %d allocations", (int) (afterBalance - beforeBalance)); +} + +// =============================================================================== + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, _Inet_BuildString); + LONGBOW_RUN_TEST_CASE(Local, _Inet6_BuildString); + LONGBOW_RUN_TEST_CASE(Local, _LinkToString); + LONGBOW_RUN_TEST_CASE(Local, _IfaceToString); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + 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(Local, _Inet_BuildString) +{ + struct sockaddr_in addr_in; + addr_in.sin_addr.s_addr = 0x04030201; + addr_in.sin_port = htons(12345); + + char *expected = "inet4://1.2.3.4:12345"; + + CPIAddress *cpiaddr = cpiAddress_CreateFromInet(&addr_in); + + PARCBufferComposer *composer = parcBufferComposer_Create(); + _Inet_BuildString(cpiaddr, composer); + + PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer); + char *actual = parcBuffer_ToString(tempBuffer); + parcBuffer_Release(&tempBuffer); + parcBufferComposer_Release(&composer); + + assertTrue(strcmp(expected, actual) == 0, "Expected '%s' actual '%s'", expected, actual); + parcMemory_Deallocate((void **) &actual); + + cpiAddress_Destroy(&cpiaddr); +} + +LONGBOW_TEST_CASE(Local, _Inet6_BuildString) +{ + struct sockaddr_in6 addr_in6; + memset(&addr_in6, 0, sizeof(struct sockaddr_in6)); + + inet_pton(AF_INET6, "2001:720:1500:1::a100", &(addr_in6.sin6_addr)); + addr_in6.sin6_family = AF_INET6; + addr_in6.sin6_port = htons(43215); + + char *expected = "inet6://[2001:720:1500:1::a100%0]:43215"; + + CPIAddress *cpiaddr = cpiAddress_CreateFromInet6(&addr_in6); + + PARCBufferComposer *composer = parcBufferComposer_Create(); + _Inet6_BuildString(cpiaddr, composer); + + PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer); + char *actual = parcBuffer_ToString(tempBuffer); + parcBuffer_Release(&tempBuffer); + parcBufferComposer_Release(&composer); + + assertTrue(strcmp(expected, actual) == 0, "Expected '%s' actual '%s'", expected, actual); + parcMemory_Deallocate((void **) &actual); + + cpiAddress_Destroy(&cpiaddr); +} + +LONGBOW_TEST_CASE(Local, _LinkToString) +{ + uint8_t addr[6] = { 0x01, 0x02, 0x03, 0xF4, 0xF5, 0xF6 }; + + char *expected = "link://01-02-03-f4-f5-f6"; + + CPIAddress *cpiaddr = cpiAddress_CreateFromLink(addr, sizeof(addr)); + + PARCBufferComposer *composer = parcBufferComposer_Create(); + _Link_BuildString(cpiaddr, composer); + + PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer); + char *actual = parcBuffer_ToString(tempBuffer); + parcBuffer_Release(&tempBuffer); + parcBufferComposer_Release(&composer); + + assertTrue(strcmp(expected, actual) == 0, "Expected '%s' actual '%s'", expected, actual); + parcMemory_Deallocate((void **) &actual); + + cpiAddress_Destroy(&cpiaddr); +} + +LONGBOW_TEST_CASE(Local, _IfaceToString) +{ + char truth_str[] = "{ .ifidx=55 }"; + + CPIAddress *cpiaddr = cpiAddress_CreateFromInterface(55); + + char output[1024]; + ssize_t output_length = _IfaceToString(output, 1024, cpiaddr->blob); + assertTrue(strcmp(output, truth_str) == 0, "Bad string, expected %s got %s", truth_str, output); + assertTrue(strlen(truth_str) == output_length, "Got wrong output size, expected %zd got %zd", strlen(truth_str), output_length); + + cpiAddress_Destroy(&cpiaddr); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_Address); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_AddressList.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_AddressList.c new file mode 100644 index 00000000..f4887a45 --- /dev/null +++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_AddressList.c @@ -0,0 +1,317 @@ +/* + * 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 "../cpi_AddressList.c" +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> + + +LONGBOW_TEST_RUNNER(cpi_AddressList) +{ + // 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(cpi_AddressList) +{ + 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(cpi_AddressList) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, cpiAddressList_Append); + LONGBOW_RUN_TEST_CASE(Global, cpiAddressList_Copy); + LONGBOW_RUN_TEST_CASE(Global, cpiAddressList_Create_Destroy); + LONGBOW_RUN_TEST_CASE(Global, cpiAddressList_GetItem); + LONGBOW_RUN_TEST_CASE(Global, cpiAddressList_Equals_same_pointer); + LONGBOW_RUN_TEST_CASE(Global, cpiAddressList_Equals_both_empty); + LONGBOW_RUN_TEST_CASE(Global, cpiAddressList_Equals_unequal_sizes); + LONGBOW_RUN_TEST_CASE(Global, cpiAddressList_Equals_same_lists); + LONGBOW_RUN_TEST_CASE(Global, cpiAddressList_Equals_wrong_order); + LONGBOW_RUN_TEST_CASE(Global, cpiAddressList_ToJSON); + LONGBOW_RUN_TEST_CASE(Global, cpiAddressList_FromJSON); + LONGBOW_RUN_TEST_CASE(Global, cpiAddressList_ToFromJSON); + LONGBOW_RUN_TEST_CASE(Global, cpiAddressList_ToString); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + 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, cpiAddressList_Append) +{ + CPIAddressList *list = cpiAddressList_Create(); + unsigned loops = 10; + + for (unsigned i = 0; i < loops; i++) { + cpiAddressList_Append(list, cpiAddress_CreateFromInterface(i)); + } + + assertTrue(cpiAddressList_Length(list) == loops, + "Got wrong length, expected %u got %zu", + loops, + cpiAddressList_Length(list)); + + cpiAddressList_Destroy(&list); +} + +LONGBOW_TEST_CASE(Global, cpiAddressList_Copy) +{ + CPIAddressList *list = cpiAddressList_Create(); + unsigned loops = 10; + + for (unsigned i = 0; i < loops; i++) { + cpiAddressList_Append(list, cpiAddress_CreateFromInterface(i)); + } + + CPIAddressList *copy = cpiAddressList_Copy(list); + assertTrue(cpiAddressList_Length(copy) == cpiAddressList_Length(list), + "Copy wrong size, got %zu expected %zu", + cpiAddressList_Length(copy), + cpiAddressList_Length(list)); + + for (unsigned i = 0; i < cpiAddressList_Length(copy); i++) { + const CPIAddress *truth = cpiAddressList_GetItem(list, i); + const CPIAddress *test = cpiAddressList_GetItem(copy, i); + assertTrue(cpiAddress_Equals(truth, test), "Lists do not match at element %u", i); + } + + cpiAddressList_Destroy(&list); + cpiAddressList_Destroy(©); +} + +LONGBOW_TEST_CASE(Global, cpiAddressList_Create_Destroy) +{ + CPIAddressList *list = cpiAddressList_Create(); + cpiAddressList_Destroy(&list); + assertTrue(parcMemory_Outstanding() == 0, "Got memory imbalance: %u", parcMemory_Outstanding()); +} + +LONGBOW_TEST_CASE(Global, cpiAddressList_GetItem) +{ + CPIAddressList *list = cpiAddressList_Create(); + unsigned loops = 10; + + for (unsigned i = 0; i < loops; i++) { + cpiAddressList_Append(list, cpiAddress_CreateFromInterface(i)); + } + + assertTrue(cpiAddressList_Length(list) == loops, + "Got wrong length, expected %u got %zu", + loops, + cpiAddressList_Length(list)); + + CPIAddress *truth = cpiAddress_CreateFromInterface(5); + const CPIAddress *test = cpiAddressList_GetItem(list, 5); + assertTrue(cpiAddress_Equals(truth, test), "Item 5 did not match!"); + + cpiAddressList_Destroy(&list); + cpiAddress_Destroy(&truth); +} + +LONGBOW_TEST_CASE(Global, cpiAddressList_Equals_same_pointer) +{ + CPIAddressList *list = cpiAddressList_Create(); + assertTrue(cpiAddressList_Equals(list, list), "list != list, that's wrong"); + cpiAddressList_Destroy(&list); +} + +LONGBOW_TEST_CASE(Global, cpiAddressList_Equals_both_empty) +{ + CPIAddressList *a = cpiAddressList_Create(); + CPIAddressList *b = cpiAddressList_Create(); + assertTrue(cpiAddressList_Equals(a, b), "emtpy list != empty list, that's wrong"); + cpiAddressList_Destroy(&a); + cpiAddressList_Destroy(&b); +} + +LONGBOW_TEST_CASE(Global, cpiAddressList_Equals_unequal_sizes) +{ + CPIAddressList *a = cpiAddressList_Create(); + CPIAddressList *b = cpiAddressList_Create(); + cpiAddressList_Append(a, cpiAddress_CreateFromInterface(1)); + assertFalse(cpiAddressList_Equals(a, b), "length 0 == length 1, that's wrong"); + cpiAddressList_Destroy(&a); + cpiAddressList_Destroy(&b); +} + +LONGBOW_TEST_CASE(Global, cpiAddressList_Equals_same_lists) +{ + CPIAddressList *a = cpiAddressList_Create(); + CPIAddressList *b = cpiAddressList_Create(); + cpiAddressList_Append(a, cpiAddress_CreateFromInterface(1)); + cpiAddressList_Append(a, cpiAddress_CreateFromInterface(2)); + cpiAddressList_Append(b, cpiAddress_CreateFromInterface(1)); + cpiAddressList_Append(b, cpiAddress_CreateFromInterface(2)); + assertTrue(cpiAddressList_Equals(a, b), "same lists not equal, that's wrong"); + cpiAddressList_Destroy(&a); + cpiAddressList_Destroy(&b); +} + +LONGBOW_TEST_CASE(Global, cpiAddressList_Equals_wrong_order) +{ + CPIAddressList *a = cpiAddressList_Create(); + CPIAddressList *b = cpiAddressList_Create(); + cpiAddressList_Append(a, cpiAddress_CreateFromInterface(1)); + cpiAddressList_Append(a, cpiAddress_CreateFromInterface(2)); + cpiAddressList_Append(b, cpiAddress_CreateFromInterface(2)); + cpiAddressList_Append(b, cpiAddress_CreateFromInterface(1)); + assertFalse(cpiAddressList_Equals(a, b), "out of order lists equal, that's wrong"); + cpiAddressList_Destroy(&a); + cpiAddressList_Destroy(&b); +} + +LONGBOW_TEST_CASE(Global, cpiAddressList_ToJSON) +{ + char truth[] = "[{\"ADDRESSTYPE\":\"IFACE\",\"DATA\":\"AAAAAA==\"},{\"ADDRESSTYPE\":\"IFACE\",\"DATA\":\"AAAAAQ==\"}]"; + + CPIAddressList *a = cpiAddressList_Create(); + int loops = 2; + for (int i = 0; i < loops; i++) { + cpiAddressList_Append(a, cpiAddress_CreateFromInterface(i)); + } + + PARCJSONArray *jsonArray = cpiAddressList_ToJson(a); + char *test = parcJSONArray_ToCompactString(jsonArray); + + assertTrue(strcmp(truth, test) == 0, "JSON strings did not match, got '%s' expected '%s'", test, truth); + + cpiAddressList_Destroy(&a); + parcMemory_Deallocate((void **) &test); + parcJSONArray_Release(&jsonArray); +} + +LONGBOW_TEST_CASE(Global, cpiAddressList_FromJSON) +{ + char json_str[] = "{\"ARRAY\":[{\"ADDRESSTYPE\":\"IFACE\",\"DATA\":\"AAAAAA==\"},{\"ADDRESSTYPE\":\"IFACE\",\"DATA\":\"AAAAAQ==\"}]}"; + PARCJSON *json = parcJSON_ParseString(json_str); + + PARCJSONArray *jsonArray = parcJSONValue_GetArray(parcJSON_GetValueByIndex(json, 0)); + + CPIAddressList *test_list = cpiAddressList_CreateFromJson(jsonArray); + + CPIAddressList *truth_list = cpiAddressList_Create(); + int loops = 2; + for (int i = 0; i < loops; i++) { + cpiAddressList_Append(truth_list, cpiAddress_CreateFromInterface(i)); + } + + assertTrue(cpiAddressList_Equals(truth_list, test_list), "Lists did not match!"); + + cpiAddressList_Destroy(&truth_list); + cpiAddressList_Destroy(&test_list); + parcJSON_Release(&json); +} + +LONGBOW_TEST_CASE(Global, cpiAddressList_ToFromJSON) +{ + CPIAddressList *truth_list = cpiAddressList_Create(); + int loops = 2; + for (int i = 0; i < loops; i++) { + cpiAddressList_Append(truth_list, cpiAddress_CreateFromInterface(i)); + } + + PARCJSONArray *json = cpiAddressList_ToJson(truth_list); + + CPIAddressList *test_list = cpiAddressList_CreateFromJson(json); + + assertTrue(cpiAddressList_Equals(truth_list, test_list), "Lists did not match!"); + + cpiAddressList_Destroy(&truth_list); + cpiAddressList_Destroy(&test_list); + parcJSONArray_Release(&json); +} + +LONGBOW_TEST_CASE(Global, cpiAddressList_ToString) +{ + CPIAddressList *truth_list = cpiAddressList_Create(); + int loops = 2; + for (int i = 0; i < loops; i++) { + cpiAddressList_Append(truth_list, cpiAddress_CreateFromInterface(i)); + } + + uint32_t beforeMemory = parcMemory_Outstanding(); + char *string = cpiAddressList_ToString(truth_list); + assertNotNull(string, "Got null string from ToString"); + parcMemory_Deallocate((void **) &string); + uint32_t afterMemory = parcMemory_Outstanding(); + + cpiAddressList_Destroy(&truth_list); + + assertTrue(beforeMemory == afterMemory, "Memory leak from ToString by %d allocations", (int) (afterMemory - beforeMemory)); +} + +// ======================================== + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, _cpiAddressList_FreeAddress); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + 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(Local, _cpiAddressList_FreeAddress) +{ + CPIAddress *address = cpiAddress_CreateFromInterface(1); + _cpiAddressList_FreeAddress((void **) &address); + + assertTrue(parcMemory_Outstanding() == 0, "Got memory imbalance: %u", parcMemory_Outstanding()); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_AddressList); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_CancelFlow.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_CancelFlow.c new file mode 100644 index 00000000..8bdc4e17 --- /dev/null +++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_CancelFlow.c @@ -0,0 +1,115 @@ +/* + * 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 "../cpi_CancelFlow.c" +#include <LongBow/unit-test.h> + +#include <parc/algol/parc_SafeMemory.h> + +#include <inttypes.h> + + + +LONGBOW_TEST_RUNNER(cpi_CancelFlow) +{ + // 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); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(cpi_CancelFlow) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(cpi_CancelFlow) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, cpiCancelFlow_CreateRequest); + LONGBOW_RUN_TEST_CASE(Global, cpiCancelFlow_NameFromControlMessage); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + 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, cpiCancelFlow_CreateRequest) +{ + const char truth_format[] = "{\"CPI_REQUEST\":{\"SEQUENCE\":%" PRIu64 ",\"CPI_CANCEL_FLOW\":{\"FLOW_NAME\":\"ccnx:/who/doesnt/like/pie\"}}}"; + + CCNxName *name = ccnxName_CreateFromCString("lci:/who/doesnt/like/pie"); + PARCJSON *cpiRequest = cpiCancelFlow_CreateRequest(name); + CCNxControl *controlRequest = ccnxControl_CreateCPIRequest(cpiRequest); + + PARCJSON *json = ccnxControl_GetJson(controlRequest); + + char buffer[1024]; + sprintf(buffer, truth_format, cpi_GetSequenceNumber(controlRequest)); + + char *test_string = parcJSON_ToCompactString(json); + assertTrue(strcmp(buffer, test_string) == 0, "Incorrect JSON, expected '%s' got '%s'", buffer, test_string); + parcMemory_Deallocate((void **) &test_string); + + ccnxControl_Release(&controlRequest); + parcJSON_Release(&cpiRequest); + ccnxName_Release(&name); +} + +LONGBOW_TEST_CASE(Global, cpiCancelFlow_NameFromControlMessage) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/who/doesnt/like/pie"); + PARCJSON *cpiRequest = cpiCancelFlow_CreateRequest(name); + CCNxControl *controlRequest = ccnxControl_CreateCPIRequest(cpiRequest); + + CCNxName *test_name = cpiCancelFlow_NameFromControlMessage(controlRequest); + assertTrue(ccnxName_Equals(test_name, name), + "Expected %s actual %s", + ccnxName_ToString(name), + ccnxName_ToString(test_name)); + + ccnxName_Release(&test_name); + ccnxControl_Release(&controlRequest); + parcJSON_Release(&cpiRequest); + ccnxName_Release(&name); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_CancelFlow); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Connection.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Connection.c new file mode 100644 index 00000000..3656611f --- /dev/null +++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Connection.c @@ -0,0 +1,220 @@ +/* + * 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 "../cpi_Connection.c" +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> + + +LONGBOW_TEST_RUNNER(cpi_Connection) +{ + // 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); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(cpi_Connection) +{ + 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(cpi_Connection) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, cpiConnection_Copy); + LONGBOW_RUN_TEST_CASE(Global, cpiConnection_Create_Destroy); + LONGBOW_RUN_TEST_CASE(Global, cpiConnection_GetAddresses); + LONGBOW_RUN_TEST_CASE(Global, cpiConnection_GetIndex); + LONGBOW_RUN_TEST_CASE(Global, cpiConnection_GetState); + LONGBOW_RUN_TEST_CASE(Global, cpiConnection_ToJSON); + LONGBOW_RUN_TEST_CASE(Global, cpiConnection_FromJSON); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + 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, cpiConnection_Copy) +{ + CPIAddress *src = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 })); + CPIAddress *dst = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x05060708 })); + CPIConnection *iptun = cpiConnection_Create(1, src, dst, cpiConnection_TCP); + + CPIConnection *copy = cpiConnection_Copy(iptun); + + assertTrue(cpiConnection_GetIndex(copy) == cpiConnection_GetIndex(iptun), + "ifidx did not match, expected %u got %u", + cpiConnection_GetIndex(iptun), + cpiConnection_GetIndex(copy)); + + assertTrue(cpiConnection_GetState(copy) == cpiConnection_GetState(iptun), + "states did not match, expected %d got %d", + cpiConnection_GetState(iptun), + cpiConnection_GetState(copy)); + + assertTrue(cpiAddress_Equals(cpiConnection_GetSourceAddress(copy), cpiConnection_GetSourceAddress(iptun)), + "did not get same source address"); + assertTrue(cpiAddress_Equals(cpiConnection_GetDestinationAddress(copy), cpiConnection_GetDestinationAddress(iptun)), + "did not get same destination address"); + + assertTrue(cpiConnection_GetConnectionType(copy) == cpiConnection_GetConnectionType(iptun), + "did not get same connection types!"); + + cpiConnection_Release(©); + cpiConnection_Release(&iptun); +} + +LONGBOW_TEST_CASE(Global, cpiConnection_Create_Destroy) +{ + CPIAddress *src = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 })); + CPIAddress *dst = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x05060708 })); + CPIConnection *iptun = cpiConnection_Create(1, src, dst, cpiConnection_GRE); + cpiConnection_Release(&iptun); + + assertTrue(parcMemory_Outstanding() == 0, "Imbalance after destroying"); +} + +LONGBOW_TEST_CASE(Global, cpiConnection_GetAddresses) +{ + CPIAddress *src = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 })); + CPIAddress *dst = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x05060708 })); + CPIConnection *iptun = cpiConnection_Create(1, src, dst, cpiConnection_TCP); + + const CPIAddress *test; + + test = cpiConnection_GetSourceAddress(iptun); + assertTrue(cpiAddress_Equals(src, test), "Address lists did not match"); + + test = cpiConnection_GetDestinationAddress(iptun); + assertTrue(cpiAddress_Equals(dst, test), "Address lists did not match"); + + cpiConnection_Release(&iptun); +} + +LONGBOW_TEST_CASE(Global, cpiConnection_GetIndex) +{ + CPIAddress *src = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 })); + CPIAddress *dst = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x05060708 })); + CPIConnection *iptun = cpiConnection_Create(1, src, dst, cpiConnection_TCP); + + assertTrue(cpiConnection_GetIndex(iptun) == 1, "ifidx did not match"); + + cpiConnection_Release(&iptun); +} + +LONGBOW_TEST_CASE(Global, cpiConnection_GetState) +{ + CPIAddress *src = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 })); + CPIAddress *dst = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x05060708 })); + CPIConnection *iptun = cpiConnection_Create(1, src, dst, cpiConnection_TCP); + + assertTrue(cpiConnection_GetState(iptun) == CPI_IFACE_UNKNOWN, "state did not match"); + + cpiConnection_SetState(iptun, CPI_IFACE_UP); + assertTrue(cpiConnection_GetState(iptun) == CPI_IFACE_UP, "state did not match"); + + cpiConnection_SetState(iptun, CPI_IFACE_DOWN); + assertTrue(cpiConnection_GetState(iptun) == CPI_IFACE_DOWN, "state did not match"); + + cpiConnection_Release(&iptun); +} + +LONGBOW_TEST_CASE(Global, cpiConnection_ToJSON) +{ + // The JSON representation depends on the system sockaddr_in format, which + // varies platform to platform. +#if defined(__APPLE__) + char *expected = "{\"Connection\":{\"IFIDX\":1,\"CONNTYPE\":\"TCP\",\"SRC\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIAAAQDAgEAAAAAAAAAAA==\"},\"DST\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIAAAgHBgUAAAAAAAAAAA==\"}}}"; +#elif defined(__linux__) + char *expected = "{\"Connection\":{\"IFIDX\":1,\"CONNTYPE\":\"TCP\",\"SRC\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAAAAQDAgEAAAAAAAAAAA==\"},\"DST\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAAAAgHBgUAAAAAAAAAAA==\"}}}"; +#else + // Case 1033 + testUnimplemented("Platform not supported"); + return; +#endif + + CPIAddress *src = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 })); + CPIAddress *dst = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x05060708 })); + CPIConnection *iptun = cpiConnection_Create(1, src, dst, cpiConnection_TCP); + + PARCJSON *test_json = cpiConnection_ToJson(iptun); + + char *actual = parcJSON_ToCompactString(test_json); + assertTrue(strcmp(expected, actual) == 0, "Expected '%s' actual '%s'", expected, actual); + + parcMemory_Deallocate((void **) &actual); + parcJSON_Release(&test_json); + cpiConnection_Release(&iptun); +} + +LONGBOW_TEST_CASE(Global, cpiConnection_FromJSON) +{ + // The JSON representation depends on the system sockaddr_in format, which + // varies platform to platform. +#if defined(__APPLE__) + char *input = "{\"Connection\":{\"IFIDX\":1,\"STATE\":\"UP\",\"CONNTYPE\":\"TCP\",\"SRC\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIAAAQDAgEAAAAAAAAAAA==\"},\"DST\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIAAAgHBgUAAAAAAAAAAA==\"}}}"; +#elif defined(__linux__) + char *input = "{\"Connection\":{\"IFIDX\":1,\"STATE\":\"UP\",\"CONNTYPE\":\"TCP\",\"SRC\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAAAAQDAgEAAAAAAAAAAA==\"},\"DST\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAAAAgHBgUAAAAAAAAAAA==\"}}}"; +#else + // Case 1033 + testUnimplemented("Platform not supported"); + return; +#endif + + CPIAddress *src = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 })); + CPIAddress *dst = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x05060708 })); + CPIConnection *expected = cpiConnection_Create(1, src, dst, cpiConnection_TCP); + cpiConnection_SetState(expected, CPI_IFACE_UP); + + PARCJSON *json = parcJSON_ParseString(input); + + CPIConnection *actual = cpiConnection_CreateFromJson(json); + assertTrue(cpiConnection_Equals(expected, actual), "Connection interfaces do not match"); + + parcJSON_Release(&json); + cpiConnection_Release(&expected); + cpiConnection_Release(&actual); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_Connection); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_ConnectionEthernet.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_ConnectionEthernet.c new file mode 100644 index 00000000..4646eccf --- /dev/null +++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_ConnectionEthernet.c @@ -0,0 +1,290 @@ +/* + * 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 "../cpi_ConnectionEthernet.c" +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> + + +typedef struct test_data { + CPIConnectionEthernet *etherConn; + + // the truth values of the connection + uint8_t macArray[6]; + CPIAddress *macAddress; + uint16_t ethertype; + char ifname[16]; + char symbolic[16]; +} TestData; + +static CPIConnectionEthernet * +conjureObject(uint8_t mac[6], uint16_t ethertype, const char *ifname, const char *symbolic) +{ + CPIAddress *macAddress = cpiAddress_CreateFromLink(mac, 6); + CPIConnectionEthernet *etherConn = cpiConnectionEthernet_Create(ifname, macAddress, ethertype, symbolic); + cpiAddress_Destroy(&macAddress); + return etherConn; +} + +static TestData * +_commonSetup(void) +{ + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData)); + + uint8_t mac[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }; + memcpy(data->macArray, mac, 6); + data->macAddress = cpiAddress_CreateFromLink(data->macArray, 6); + data->ethertype = 0x0801; + sprintf(data->ifname, "em1"); + sprintf(data->symbolic, "conn0"); + + data->etherConn = cpiConnectionEthernet_Create(data->ifname, data->macAddress, data->ethertype, data->symbolic); + return data; +} + +static void +_commonTeardown(TestData *data) +{ + cpiConnectionEthernet_Release(&data->etherConn); + cpiAddress_Destroy(&data->macAddress); + parcMemory_Deallocate((void **) &data); +} + +LONGBOW_TEST_RUNNER(cpi_ConnectionEthernet) +{ + // 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); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(cpi_ConnectionEthernet) +{ + 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(cpi_ConnectionEthernet) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, cpiConnectionEthernet_Create); + LONGBOW_RUN_TEST_CASE(Global, cpiConnectionEthernet_CreateAddMessage); + LONGBOW_RUN_TEST_CASE(Global, cpiConnectionEthernet_CreateRemoveMessage); + LONGBOW_RUN_TEST_CASE(Global, cpiConnectionEthernet_FromControl); + LONGBOW_RUN_TEST_CASE(Global, cpiConnectionEthernet_GetPeerLinkAddress); + LONGBOW_RUN_TEST_CASE(Global, cpiConnectionEthernet_GetEthertype); + LONGBOW_RUN_TEST_CASE(Global, cpiConnectionEthernet_GetEthertype); + LONGBOW_RUN_TEST_CASE(Global, cpiConnectionEthernet_GetInterfaceName); + LONGBOW_RUN_TEST_CASE(Global, cpiConnectionEthernet_IsAddMessage); + LONGBOW_RUN_TEST_CASE(Global, cpiConnectionEthernet_IsRemoveMessage); + LONGBOW_RUN_TEST_CASE(Global, cpiConnectionEthernet_Equals); +} + +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; +} + +LONGBOW_TEST_CASE(Global, cpiConnectionEthernet_Create) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + size_t beforeBalance = parcMemory_Outstanding(); + CPIConnectionEthernet *etherConn = cpiConnectionEthernet_Create(data->ifname, data->macAddress, data->ethertype, data->symbolic); + cpiConnectionEthernet_Release(ðerConn); + size_t afterBalance = parcMemory_Outstanding(); + + assertTrue(afterBalance == beforeBalance, + "Memory imbalance on create/destroy, before %zu afer %zu", + beforeBalance, afterBalance); +} + +LONGBOW_TEST_CASE(Global, cpiConnectionEthernet_Equals) +{ + uint8_t mac_a[6] = { 1, 2, 3, 4, 5, 6 }; + uint8_t mac_b[6] = { 9, 8, 7, 6, 5, 4 }; + + CPIConnectionEthernet *x = conjureObject(mac_a, 0x0123, "happy", "puppy"); + CPIConnectionEthernet *y = conjureObject(mac_a, 0x0123, "happy", "puppy"); + CPIConnectionEthernet *z = conjureObject(mac_a, 0x0123, "happy", "puppy"); + + CPIConnectionEthernet *u = conjureObject(mac_b, 0x0123, "happy", "puppy"); + CPIConnectionEthernet *v = conjureObject(mac_a, 0x7777, "happy", "puppy"); + CPIConnectionEthernet *w = conjureObject(mac_a, 0x0123, "sad", "kitten"); + + assertEqualsContract(cpiConnectionEthernet_Equals, x, y, z, u, v, w); + + cpiConnectionEthernet_Release(&x); + cpiConnectionEthernet_Release(&y); + cpiConnectionEthernet_Release(&z); + cpiConnectionEthernet_Release(&u); + cpiConnectionEthernet_Release(&v); + cpiConnectionEthernet_Release(&w); +} + + +LONGBOW_TEST_CASE(Global, cpiConnectionEthernet_CreateAddMessage) +{ + const char *truthStringFormat = "{ \"CPI_REQUEST\" : { \"SEQUENCE\" : %d, \"%s\" : { \"IFNAME\" : \"em1\", \"SYMBOLIC\" : \"conn0\", \"PEER_ADDR\" : { \"ADDRESSTYPE\" : \"LINK\", \"DATA\" : \"AQIDBAUG\" }, \"ETHERTYPE\" : 2049 } } }"; + + char buffer[1024]; + + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + CCNxControl *control = cpiConnectionEthernet_CreateAddMessage(data->etherConn); + + if (ccnxControl_IsCPI(control)) { + PARCJSON *testJson = ccnxControl_GetJson(control); + assertNotNull(testJson, "Got null json from control message"); + uint64_t seqnum = controlPlaneInterface_GetSequenceNumber(testJson); + sprintf(buffer, truthStringFormat, (int) seqnum, KEY_ADDETHER); + + PARCJSON *truthJson = parcJSON_ParseString(buffer); + assertTrue(parcJSON_Equals(truthJson, testJson), "JSON not correct in Add Connection Ethernet") + { + char *a = parcJSON_ToString(testJson); + printf("Got: \n%s\n", a); + parcMemory_Deallocate((void **) &a); + + printf("Expected\n%s\n", buffer); + } + + parcJSON_Release(&truthJson); + } + ccnxControl_Release(&control); +} + +LONGBOW_TEST_CASE(Global, cpiConnectionEthernet_CreateRemoveMessage) +{ + const char *truthStringFormat = "{ \"CPI_REQUEST\" : { \"SEQUENCE\" : %d, \"%s\" : { \"IFNAME\" : \"em1\", \"SYMBOLIC\" : \"conn0\", \"PEER_ADDR\" : { \"ADDRESSTYPE\" : \"LINK\", \"DATA\" : \"AQIDBAUG\" }, \"ETHERTYPE\" : 2049 } } }"; + + char buffer[1024]; + + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + CCNxControl *control = cpiConnectionEthernet_CreateRemoveMessage(data->etherConn); + + if (ccnxControl_IsCPI(control)) { + PARCJSON *testJson = ccnxControl_GetJson(control); + assertNotNull(testJson, "Got null json from control message"); + uint64_t seqnum = controlPlaneInterface_GetSequenceNumber(testJson); + sprintf(buffer, truthStringFormat, (int) seqnum, KEY_REMOVEETHER); + + PARCJSON *truthJson = parcJSON_ParseString(buffer); + assertTrue(parcJSON_Equals(truthJson, testJson), "JSON not correct in Remove Connection Ethernet") + { + char *a = parcJSON_ToString(testJson); + printf("Got: \n%s\n", a); + parcMemory_Deallocate((void **) &a); + + printf("Expected\n%s\n", buffer); + } + + parcJSON_Release(&truthJson); + } + ccnxControl_Release(&control); +} + +LONGBOW_TEST_CASE(Global, cpiConnectionEthernet_FromControl) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxControl *addMessage = cpiConnectionEthernet_CreateAddMessage(data->etherConn); + + CPIConnectionEthernet *test = cpiConnectionEthernet_FromControl(addMessage); + + assertNotNull(test, "Got null object parsing json: %s\n", parcJSON_ToString(ccnxControl_GetJson(addMessage))); + + assertTrue(cpiConnectionEthernet_Equals(test, data->etherConn), "Object from control did not equal true value"); + + cpiConnectionEthernet_Release(&test); + ccnxControl_Release(&addMessage); +} + +LONGBOW_TEST_CASE(Global, cpiConnectionEthernet_GetPeerLinkAddress) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + CPIAddress *test = cpiConnectionEthernet_GetPeerLinkAddress(data->etherConn); + assertTrue(cpiAddress_Equals(test, data->macAddress), "Wrong mac address"); +} + + +LONGBOW_TEST_CASE(Global, cpiConnectionEthernet_GetEthertype) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + uint16_t test = cpiConnectionEthernet_GetEthertype(data->etherConn); + assertTrue(test == data->ethertype, "Wrong ethertype, got %04X expected %04X", test, data->ethertype); +} + +LONGBOW_TEST_CASE(Global, cpiConnectionEthernet_GetInterfaceName) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + const char *test = cpiConnectionEthernet_GetInterfaceName(data->etherConn); + assertTrue(strcmp(test, data->ifname) == 0, "Wrong interface name, got '%s' expected '%s'", test, data->ifname); +} + +LONGBOW_TEST_CASE(Global, cpiConnectionEthernet_IsAddMessage) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + CCNxControl *control = cpiConnectionEthernet_CreateAddMessage(data->etherConn); + bool isAdd = cpiConnectionEthernet_IsAddMessage(control); + ccnxControl_Release(&control); + + assertTrue(isAdd, "Add Connection Ethernet message did not report as such a message."); +} + +LONGBOW_TEST_CASE(Global, cpiConnectionEthernet_IsRemoveMessage) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + + CCNxControl *control = cpiConnectionEthernet_CreateRemoveMessage(data->etherConn); + bool isRemove = cpiConnectionEthernet_IsRemoveMessage(control); + ccnxControl_Release(&control); + + assertTrue(isRemove, "Remove Connection Ethernet message did not report as such a message."); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_ConnectionEthernet); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_ConnectionList.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_ConnectionList.c new file mode 100644 index 00000000..c624866a --- /dev/null +++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_ConnectionList.c @@ -0,0 +1,186 @@ +/* + * 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 "../cpi_ConnectionList.c" +#include <LongBow/unit-test.h> + +#include <parc/algol/parc_SafeMemory.h> + + + +LONGBOW_TEST_RUNNER(cpi_ConnectionList) +{ + // 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); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(cpi_ConnectionList) +{ + 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(cpi_ConnectionList) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, cpiConnectionList_Append); + LONGBOW_RUN_TEST_CASE(Global, cpiConnectionList_Create_Destroy); + LONGBOW_RUN_TEST_CASE(Global, cpiConnectionList_FromJson); + LONGBOW_RUN_TEST_CASE(Global, cpiConnectionList_Equals); + LONGBOW_RUN_TEST_CASE(Global, cpiConnectionList_ToJson); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + 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; +} + +static CPIConnection * +createConnectionObject(unsigned ifidx, int s_addr, uint16_t s_port, int d_addr, uint16_t d_port) +{ + return cpiConnection_Create(ifidx, + cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_family = PF_INET, .sin_addr.s_addr = s_addr, .sin_port = s_port }), + cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_family = PF_INET, .sin_addr.s_addr = d_addr, .sin_port = d_port }), + cpiConnection_TCP); +} + +LONGBOW_TEST_CASE(Global, cpiConnectionList_Append) +{ + CPIConnectionList *list = cpiConnectionList_Create(); + cpiConnectionList_Append(list, createConnectionObject(1, 2, 3, 4, 5)); + + assertTrue(parcArrayList_Size(list->listOfConnections) == 1, "got wrong size, expected %u got %zu", 1, parcArrayList_Size(list->listOfConnections)); + + cpiConnectionList_Destroy(&list); +} + +LONGBOW_TEST_CASE(Global, cpiConnectionList_Create_Destroy) +{ + CPIConnectionList *list = cpiConnectionList_Create(); + cpiConnectionList_Destroy(&list); + assertTrue(parcMemory_Outstanding() == 0, "Memory imbalance after create/destroy"); +} + +LONGBOW_TEST_CASE(Global, cpiConnectionList_FromJson) +{ + // The JSON representation depends on the system sockaddr_in format, which + // varies platform to platform. +#if defined(__APPLE__) + char truth_string[] = "{\"ConnectionList\":[{\"Connection\":{\"IFIDX\":1,\"CONNTYPE\":\"TCP\",\"SRC\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIDAAIAAAAAAAAAAAAAAA==\"},\"DST\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIFAAQAAAAAAAAAAAAAAA==\"}}}]}"; +#elif defined(__linux__) + char truth_string[] = "{\"ConnectionList\":[{\"Connection\":{\"IFIDX\":1,\"CONNTYPE\":\"TCP\",\"SRC\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgADAAIAAAAAAAAAAAAAAA==\"},\"DST\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAFAAQAAAAAAAAAAAAAAA==\"}}}]}"; +#else + // Case 1033 + testUnimplemented("Platform not supported"); + return; +#endif + + CPIConnectionList *truth_list = cpiConnectionList_Create(); + cpiConnectionList_Append(truth_list, createConnectionObject(1, 2, 3, 4, 5)); + + PARCJSON *truth_json = parcJSON_ParseString(truth_string); + CPIConnectionList *test_list = cpiConnectionList_FromJson(truth_json); + + assertTrue(cpiConnectionList_Equals(truth_list, test_list), "Lists do not match"); + + cpiConnectionList_Destroy(&test_list); + parcJSON_Release(&truth_json); + cpiConnectionList_Destroy(&truth_list); +} + +LONGBOW_TEST_CASE(Global, cpiConnectionList_Equals) +{ + CPIConnectionList *list_a = cpiConnectionList_Create(); + cpiConnectionList_Append(list_a, createConnectionObject(1, 2, 3, 4, 5)); + + CPIConnectionList *list_b = cpiConnectionList_Create(); + cpiConnectionList_Append(list_b, createConnectionObject(1, 2, 3, 4, 5)); + + CPIConnectionList *list_c = cpiConnectionList_Create(); + cpiConnectionList_Append(list_c, createConnectionObject(1, 2, 3, 4, 5)); + + CPIConnectionList *unequal = cpiConnectionList_Create(); + cpiConnectionList_Append(unequal, createConnectionObject(99, 2, 3, 4, 5)); + cpiConnectionList_Append(unequal, createConnectionObject(1, 99, 3, 4, 5)); + cpiConnectionList_Append(unequal, createConnectionObject(1, 2, 99, 4, 5)); + cpiConnectionList_Append(unequal, createConnectionObject(1, 2, 3, 99, 5)); + cpiConnectionList_Append(unequal, createConnectionObject(1, 2, 3, 4, 99)); + + assertEqualsContract(cpiConnectionList_Equals, list_a, list_b, list_c, unequal); + + cpiConnectionList_Destroy(&unequal); + cpiConnectionList_Destroy(&list_a); + cpiConnectionList_Destroy(&list_b); + cpiConnectionList_Destroy(&list_c); +} + +LONGBOW_TEST_CASE(Global, cpiConnectionList_ToJson) +{ + // The JSON representation depends on the system sockaddr_in format, which + // varies platform to platform. +#if defined(__APPLE__) + char truth_string[] = "{\"ConnectionList\":[{\"Connection\":{\"IFIDX\":1,\"CONNTYPE\":\"TCP\",\"SRC\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIDAAIAAAAAAAAAAAAAAA==\"},\"DST\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIFAAQAAAAAAAAAAAAAAA==\"}}}]}"; +#elif defined(__linux__) + char truth_string[] = "{\"ConnectionList\":[{\"Connection\":{\"IFIDX\":1,\"CONNTYPE\":\"TCP\",\"SRC\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgADAAIAAAAAAAAAAAAAAA==\"},\"DST\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAFAAQAAAAAAAAAAAAAAA==\"}}}]}"; +#else + // Case 1033 + testUnimplemented("Platform not supported"); + return; +#endif + + + CPIConnectionList *list = cpiConnectionList_Create(); + cpiConnectionList_Append(list, createConnectionObject(1, 2, 3, 4, 5)); + + PARCJSON *json = cpiConnectionList_ToJson(list); + char *test = parcJSON_ToCompactString(json); + assertTrue(strcmp(truth_string, test) == 0, "Got wrong JSON.\nexpected: %s\ngot %s\n", truth_string, test); + parcMemory_Deallocate((void **) &test); + + parcJSON_Release(&json); + cpiConnectionList_Destroy(&list); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_ConnectionList); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_ControlFacade.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_ControlFacade.c new file mode 100644 index 00000000..17e04299 --- /dev/null +++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_ControlFacade.c @@ -0,0 +1,220 @@ +/* + * 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 "../cpi_ControlFacade.c" + +#include <parc/algol/parc_SafeMemory.h> + +#include <ccnx/transport/common/transport_MetaMessage.h> + +#include <LongBow/unit-test.h> + +typedef struct test_data { + char *jsonstring; + PARCJSON *json; +} TestData; + +static TestData * +_commonSetup(void) +{ + TestData *data = parcMemory_AllocateAndClear(sizeof(TestData)); + assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData)); + data->jsonstring = parcMemory_StringDuplicate("{ \"EMPTY\": \"NESS\" }", 100); + data->json = parcJSON_ParseString(data->jsonstring); + assertNotNull(data->json, "got null JSON from string: %s", data->jsonstring); + + return data; +} + +static void +_commonTeardown(TestData *data) +{ + parcJSON_Release(&data->json); + parcMemory_Deallocate((void **) &(data->jsonstring)); + parcMemory_Deallocate((void **) &data); +} + +LONGBOW_TEST_RUNNER(ccnx_ControlFacade) +{ + // 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(ccnx_ControlFacade) +{ + 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(ccnx_ControlFacade) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxControlFacade_CreateControlMessage_Notification); + + LONGBOW_RUN_TEST_CASE(Global, ccnxControlFacade_AssertValid); + LONGBOW_RUN_TEST_CASE(Global, ccnxControlFacade_CreateCPI); + LONGBOW_RUN_TEST_CASE(Global, ccnxControlFacade_CreateNotification); + LONGBOW_RUN_TEST_CASE(Global, ccnxControlFacade_GetJson); + LONGBOW_RUN_TEST_CASE(Global, ccnxControlFacade_IsCPI); + LONGBOW_RUN_TEST_CASE(Global, ccnxControlFacade_IsNotification); + LONGBOW_RUN_TEST_CASE(Global, ccnxControlFacade_Display); + LONGBOW_RUN_TEST_CASE(Global, ccnxControlFacade_ToString); +} + +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; +} + +LONGBOW_TEST_CASE(Global, ccnxControlFacade_CreateControlMessage_Notification) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxMetaMessage *control = ccnxControlFacade_CreateNotification(data->json); + + CCNxControl *cpiControl = ccnxMetaMessage_GetControl(control); + + assertNotNull(cpiControl, "Got null control message"); + + ccnxMetaMessage_Release(&control); +} + +LONGBOW_TEST_CASE(Global, ccnxControlFacade_AssertValid) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxTlvDictionary *control = ccnxControlFacade_CreateCPI(data->json); + ccnxControlFacade_AssertValid(control); + ccnxTlvDictionary_Release(&control); +} + +LONGBOW_TEST_CASE(Global, ccnxControlFacade_CreateCPI) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxTlvDictionary *control = ccnxControlFacade_CreateCPI(data->json); + ccnxControlFacade_AssertValid(control); + ccnxTlvDictionary_Release(&control); +} + +LONGBOW_TEST_CASE(Global, ccnxControlFacade_CreateNotification) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxTlvDictionary *control = ccnxControlFacade_CreateNotification(data->json); + ccnxControlFacade_AssertValid(control); + ccnxTlvDictionary_Release(&control); +} + +LONGBOW_TEST_CASE(Global, ccnxControlFacade_GetJson) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxTlvDictionary *control = ccnxControlFacade_CreateNotification(data->json); + + PARCJSON *json = ccnxControlFacade_GetJson(control); + + char *test = parcJSON_ToCompactString(json); + char *truth = parcJSON_ToCompactString(data->json); + + assertTrue(strcmp(test, truth) == 0, "Wrong JSON\ngot %s\nexpected %s\n", test, truth); + + parcMemory_Deallocate((void **) &test); + parcMemory_Deallocate((void **) &truth); + ccnxTlvDictionary_Release(&control); +} + +LONGBOW_TEST_CASE(Global, ccnxControlFacade_IsCPI) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxTlvDictionary *control = ccnxControlFacade_CreateCPI(data->json); + assertTrue(ccnxControlFacade_IsCPI(control), "Notification says its not a notification"); + ccnxTlvDictionary_Release(&control); +} + +LONGBOW_TEST_CASE(Global, ccnxControlFacade_IsNotification) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxTlvDictionary *control = ccnxControlFacade_CreateNotification(data->json); + assertTrue(ccnxControlFacade_IsNotification(control), "Notification says its not a notification"); + ccnxTlvDictionary_Release(&control); +} + +LONGBOW_TEST_CASE(Global, ccnxControlFacade_Display) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxTlvDictionary *control = ccnxControlFacade_CreateNotification(data->json); + ccnxControlFacade_Display(control, 1); + ccnxTlvDictionary_Release(&control); +} + +LONGBOW_TEST_CASE(Global, ccnxControlFacade_ToString) +{ + TestData *data = longBowTestCase_GetClipBoardData(testCase); + CCNxTlvDictionary *control = ccnxControlFacade_CreateNotification(data->json); + char *desc = ccnxControlFacade_ToString(control); + + assertNotNull(desc, "Expected a string"); + printf("%s\n", desc); + + parcMemory_Deallocate((void **) &desc); + ccnxTlvDictionary_Release(&control); +} +LONGBOW_TEST_FIXTURE(Local) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + 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; +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(ccnx_ControlFacade); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_ControlMessage.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_ControlMessage.c new file mode 100644 index 00000000..82b687b2 --- /dev/null +++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_ControlMessage.c @@ -0,0 +1,378 @@ +/* + * 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 Runner. +#include "../cpi_ControlMessage.c" + +#include <stdio.h> + +#include <arpa/inet.h> +#include <LongBow/unit-test.h> + +#include <parc/algol/parc_SafeMemory.h> +#include <ccnx/api/control/cpi_InterfaceIPTunnel.h> + +LONGBOW_TEST_RUNNER(cpi_ControlMessage) +{ + parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory); + + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(cpi_ControlMessage) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(cpi_ControlMessage) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ccnxControl_AcquireRelease); + LONGBOW_RUN_TEST_CASE(Global, ccnxControl_CreateAddRouteRequest); + LONGBOW_RUN_TEST_CASE(Global, ccnxControl_CreateAddRouteToSelfRequest); + LONGBOW_RUN_TEST_CASE(Global, ccnxControl_CreateCPIRequest); + LONGBOW_RUN_TEST_CASE(Global, ccnxControl_CreateCancelFlowRequest); + LONGBOW_RUN_TEST_CASE(Global, ccnxControl_CreateConnectionListRequest); + LONGBOW_RUN_TEST_CASE(Global, ccnxControl_CreateIPTunnelRequest); + LONGBOW_RUN_TEST_CASE(Global, ccnxControl_CreateInterfaceListRequest); + LONGBOW_RUN_TEST_CASE(Global, ccnxControl_CreatePauseInputRequest); + LONGBOW_RUN_TEST_CASE(Global, ccnxControl_CreateRemoveRouteRequest); + LONGBOW_RUN_TEST_CASE(Global, ccnxControl_CreateRemoveRouteToSelfRequest); + LONGBOW_RUN_TEST_CASE(Global, ccnxControl_CreateRouteListRequest); + LONGBOW_RUN_TEST_CASE(Global, ccnxControl_Display); + LONGBOW_RUN_TEST_CASE(Global, ccnxControl_GetAckOriginalSequenceNumber); + LONGBOW_RUN_TEST_CASE(Global, ccnxControl_GetJson); + LONGBOW_RUN_TEST_CASE(Global, ccnxControl_GetNotifyStatus); + LONGBOW_RUN_TEST_CASE(Global, ccnxControl_IsACK); + LONGBOW_RUN_TEST_CASE(Global, ccnxControl_IsCPI); + LONGBOW_RUN_TEST_CASE(Global, ccnxControl_IsNotification); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) { + printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding()); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, ccnxControl_AcquireRelease) +{ + CCNxControl *control = ccnxControl_CreateInterfaceListRequest(); + CCNxControl *reference = ccnxControl_Acquire(control); + + ccnxControl_Release(&control); + + assertNull(control, "Expected control to be null"); + assertNotNull(reference, "Expected acquired reference to be non null"); + ccnxControl_Release(&reference); + assertNull(reference, "Expected reference to be null"); +} + +LONGBOW_TEST_CASE(Global, ccnxControl_CreateAddRouteRequest) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/boose/roo/pie"); + CPIRouteEntry *route = cpiRouteEntry_CreateRouteToSelf(name); + CCNxControl *control = ccnxControl_CreateAddRouteRequest(route); + + assertNotNull(control, "Expected control message to be non null"); + assertTrue(ccnxControl_IsCPI(control), "Expected control to be a CPI control message"); + + PARCJSON *json = ccnxControl_GetJson(control); + assertTrue(cpi_getCPIOperation2(json) == CPI_REGISTER_PREFIX, + "Expected operation %d got %d", CPI_REGISTER_PREFIX, cpi_getCPIOperation2(json)); + ccnxControl_Release(&control); + ccnxName_Release(&name); + cpiRouteEntry_Destroy(&route); +} + +LONGBOW_TEST_CASE(Global, ccnxControl_CreateAddRouteToSelfRequest) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/boose/roo/pie"); + CCNxControl *control = ccnxControl_CreateAddRouteToSelfRequest(name); + + assertNotNull(control, "Expected control message to be non null"); + assertTrue(ccnxControl_IsCPI(control), "Expected control to be a CPI control message"); + + PARCJSON *json = ccnxControl_GetJson(control); + assertTrue(cpi_getCPIOperation2(json) == CPI_REGISTER_PREFIX, + "Expected operation %d got %d", CPI_REGISTER_PREFIX, cpi_getCPIOperation2(json)); + + ccnxControl_Release(&control); + ccnxName_Release(&name); +} + + +LONGBOW_TEST_CASE(Global, ccnxControl_CreateCancelFlowRequest) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/boose/roo/pie"); + CCNxControl *control = ccnxControl_CreateCancelFlowRequest(name); + assertNotNull(control, "Expected control message to be non null"); + assertTrue(ccnxControl_IsCPI(control), "Expected control to be a CPI control message"); + + PARCJSON *json = ccnxControl_GetJson(control); + assertTrue(cpi_getCPIOperation2(json) == CPI_CANCEL_FLOW, + "Expected operation %d got %d", CPI_CANCEL_FLOW, cpi_getCPIOperation2(json)); + + ccnxControl_Release(&control); + ccnxName_Release(&name); +} + +LONGBOW_TEST_CASE(Global, ccnxControl_CreatePauseInputRequest) +{ + CCNxControl *control = ccnxControl_CreatePauseInputRequest(); + assertNotNull(control, "Expected control message to be non null"); + assertTrue(ccnxControl_IsCPI(control), "Expected control to be a CPI control message"); + + PARCJSON *json = ccnxControl_GetJson(control); + assertTrue(cpi_getCPIOperation2(json) == CPI_PAUSE, + "Expected operation %d got %d", CPI_PAUSE, cpi_getCPIOperation2(json)); + ccnxControl_Release(&control); +} + +LONGBOW_TEST_CASE(Global, ccnxControl_CreateConnectionListRequest) +{ + CCNxControl *control = ccnxControl_CreateConnectionListRequest(); + assertNotNull(control, "Expected control message to be non null"); + assertTrue(ccnxControl_IsCPI(control), "Expected control to be a CPI control message"); + + PARCJSON *json = ccnxControl_GetJson(control); + assertTrue(cpi_getCPIOperation2(json) == CPI_CONNECTION_LIST, + "Expected operation %d got %d", CPI_CONNECTION_LIST, cpi_getCPIOperation2(json)); + ccnxControl_Release(&control); +} + +LONGBOW_TEST_CASE(Global, ccnxControl_CreateIPTunnelRequest) +{ + struct sockaddr_in sockaddr_any; + memset(&sockaddr_any, 0, sizeof(sockaddr_any)); + sockaddr_any.sin_family = PF_INET; + sockaddr_any.sin_addr.s_addr = INADDR_ANY; + + CPIAddress *source = cpiAddress_CreateFromInet(&sockaddr_any); + + struct sockaddr_in sockaddr_dst; + memset(&sockaddr_dst, 0, sizeof(sockaddr_dst)); + sockaddr_dst.sin_family = PF_INET; + sockaddr_dst.sin_port = htons(9999); + inet_pton(AF_INET, "127.0.0.1", &(sockaddr_dst.sin_addr)); + + CPIAddress *destination = cpiAddress_CreateFromInet(&sockaddr_dst); + + CPIInterfaceIPTunnel *tunnel = cpiInterfaceIPTunnel_Create(0, source, destination, IPTUN_TCP, "tun0"); + CCNxControl *control = ccnxControl_CreateIPTunnelRequest(tunnel); + + assertNotNull(control, "Expected control message to be non null"); + assertTrue(ccnxControl_IsCPI(control), "Expected control to be a CPI control message"); + + PARCJSON *json = ccnxControl_GetJson(control); + assertTrue(cpi_getCPIOperation2(json) == CPI_CREATE_TUNNEL, + "Expected operation %d got %d", CPI_CREATE_TUNNEL, cpi_getCPIOperation2(json)); + + ccnxControl_Release(&control); + cpiInterfaceIPTunnel_Release(&tunnel); +} + +LONGBOW_TEST_CASE(Global, ccnxControl_CreateInterfaceListRequest) +{ + CCNxControl *control = ccnxControl_CreateInterfaceListRequest(); + assertNotNull(control, "Expected control message to be non null"); + assertTrue(ccnxControl_IsCPI(control), "Expected control to be a CPI control message"); + + PARCJSON *json = ccnxControl_GetJson(control); + assertTrue(cpi_getCPIOperation2(json) == CPI_INTERFACE_LIST, + "Expected operation %d got %d", CPI_INTERFACE_LIST, cpi_getCPIOperation2(json)); + ccnxControl_Release(&control); +} + +LONGBOW_TEST_CASE(Global, ccnxControl_CreateRemoveRouteRequest) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/boose/roo/pie"); + CPIRouteEntry *route = cpiRouteEntry_CreateRouteToSelf(name); + CCNxControl *control = ccnxControl_CreateRemoveRouteRequest(route); + + assertNotNull(control, "Expected control message to be non null"); + assertTrue(ccnxControl_IsCPI(control), "Expected control to be a CPI control message"); + + PARCJSON *json = ccnxControl_GetJson(control); + assertTrue(cpi_getCPIOperation2(json) == CPI_UNREGISTER_PREFIX, + "Expected operation %d got %d", CPI_UNREGISTER_PREFIX, cpi_getCPIOperation2(json)); + + ccnxControl_Release(&control); + ccnxName_Release(&name); + cpiRouteEntry_Destroy(&route); +} + +LONGBOW_TEST_CASE(Global, ccnxControl_CreateRemoveRouteToSelfRequest) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/boose/roo/pie"); + CCNxControl *control = ccnxControl_CreateRemoveRouteToSelfRequest(name); + + assertNotNull(control, "Expected control message to be non null"); + assertTrue(ccnxControl_IsCPI(control), "Expected control to be a CPI control message"); + + PARCJSON *json = ccnxControl_GetJson(control); + assertTrue(cpi_getCPIOperation2(json) == CPI_UNREGISTER_PREFIX, + "Expected operation %d got %d", CPI_UNREGISTER_PREFIX, cpi_getCPIOperation2(json)); + + ccnxControl_Release(&control); + ccnxName_Release(&name); +} + +LONGBOW_TEST_CASE(Global, ccnxControl_CreateRouteListRequest) +{ + CCNxControl *control = ccnxControl_CreateRouteListRequest(); + assertNotNull(control, "Expected control message to be non null"); + assertTrue(ccnxControl_IsCPI(control), "Expected control to be a CPI control message"); + + PARCJSON *json = ccnxControl_GetJson(control); + assertTrue(cpi_getCPIOperation2(json) == CPI_PREFIX_REGISTRATION_LIST, + "Expected operation %d got %d", CPI_PREFIX_REGISTRATION_LIST, cpi_getCPIOperation2(json)); + + ccnxControl_Release(&control); +} + +LONGBOW_TEST_CASE(Global, ccnxControl_CreateCPIRequest) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/boose/roo/pie"); + PARCJSON *cpiRequest = cpiCancelFlow_CreateRequest(name); + + CCNxControl *control = ccnxControl_CreateCPIRequest(cpiRequest); + + assertTrue(ccnxControl_IsCPI(control), "Expected control to be a CPI control message"); + + parcJSON_Release(&cpiRequest); + ccnxControl_Release(&control); + ccnxName_Release(&name); +} + +LONGBOW_TEST_CASE(Global, ccnxControl_Display) +{ + CCNxControl *control = ccnxControl_CreateRouteListRequest(); + ccnxControl_Display(control, 4); + ccnxControl_Release(&control); +} + +LONGBOW_TEST_CASE(Global, ccnxControl_GetAckOriginalSequenceNumber) +{ + CCNxControl *control = ccnxControl_CreateRouteListRequest(); + assertNotNull(control, "Expected control message to be non null"); + assertTrue(ccnxControl_IsCPI(control), "Expected control to be a CPI control message"); + + PARCJSON *json = ccnxControl_GetJson(control); + PARCJSON *jsonAck = cpiAcks_CreateAck(json); + + CCNxControl *response = ccnxControl_CreateCPIRequest(jsonAck); + + // Calling GetAckOriginalSequenceNumber() to make sure the path works. We don't care + // about the value. + /*uint64_t originalSequenceNumber = */ ccnxControl_GetAckOriginalSequenceNumber(response); + + ccnxControl_Release(&control); + ccnxControl_Release(&response); + parcJSON_Release(&jsonAck); +} + +LONGBOW_TEST_CASE(Global, ccnxControl_GetJson) +{ + CCNxControl *control = ccnxControl_CreateRouteListRequest(); + PARCJSON *json = ccnxControl_GetJson(control); + assertNotNull(json, "Expected some JSON"); + ccnxControl_Release(&control); +} + +LONGBOW_TEST_CASE(Global, ccnxControl_IsACK) +{ + CCNxControl *control = ccnxControl_CreateRouteListRequest(); + assertNotNull(control, "Expected control message to be non null"); + assertTrue(ccnxControl_IsCPI(control), "Expected control to be a CPI control message"); + + PARCJSON *json = ccnxControl_GetJson(control); + PARCJSON *jsonAck = cpiAcks_CreateAck(json); + + CCNxControl *response = ccnxControl_CreateCPIRequest(jsonAck); + + assertTrue(ccnxControl_IsACK(response), "Expected the message to be an Ack"); + + ccnxControl_Release(&control); + ccnxControl_Release(&response); + parcJSON_Release(&jsonAck); +} + +LONGBOW_TEST_CASE(Global, ccnxControl_IsCPI) +{ + CCNxControl *control = ccnxControl_CreateRouteListRequest(); + assertTrue(ccnxControl_IsCPI(control), "Expected a CPI Message"); + ccnxControl_Release(&control); +} + +LONGBOW_TEST_CASE(Global, ccnxControl_IsNotification) +{ + PARCJSON *json = parcJSON_Create(); + CCNxMetaMessage *notification = ccnxControlFacade_CreateNotification(json); + CCNxControl *control = ccnxMetaMessage_GetControl(notification); + + assertTrue(ccnxControl_IsNotification(control), "Expected a notification"); + assertFalse(ccnxControl_IsCPI(control), "Did not expect a CPI command"); + + parcJSON_Release(&json); + ccnxTlvDictionary_Release(¬ification); +} + +LONGBOW_TEST_CASE(Global, ccnxControl_GetNotifyStatus) +{ + CCNxName *name = ccnxName_CreateFromCString("lci:/boose/roo/pie"); + + NotifyStatus *expected = notifyStatus_Create(1, notifyStatusCode_CONNECTION_OPEN, name, "There's a spider behind you."); + + PARCJSON *json = notifyStatus_ToJSON(expected); + CCNxMetaMessage *notification = ccnxControlFacade_CreateNotification(json); + CCNxControl *control = ccnxMetaMessage_GetControl(notification); + + assertTrue(ccnxControl_IsNotification(control), "Expected a notification"); + NotifyStatus *status = ccnxControl_GetNotifyStatus(control); + + assertTrue(ccnxName_Equals(notifyStatus_GetName(expected), notifyStatus_GetName(status)), "Expected equal names"); + assertTrue(notifyStatus_GetStatusCode(expected) == notifyStatus_GetStatusCode(status), "Expected equal status codes"); + assertTrue(strcmp(notifyStatus_GetMessage(expected), notifyStatus_GetMessage(status)) == 0, "Expected equal messages"); + + parcJSON_Release(&json); + ccnxTlvDictionary_Release(¬ification); + ccnxName_Release(&name); + notifyStatus_Release(&status); + notifyStatus_Release(&expected); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_ControlMessage); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Forwarding.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Forwarding.c new file mode 100644 index 00000000..ecaa569f --- /dev/null +++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Forwarding.c @@ -0,0 +1,331 @@ +/* + * 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 "../cpi_Forwarding.c" + +#include <parc/algol/parc_Memory.h> +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +#include <inttypes.h> + + + +LONGBOW_TEST_RUNNER(cpi_Forwarding) +{ + // 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); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(cpi_Forwarding) +{ + 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(cpi_Forwarding) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, cpiForwarding_AddRoute_1); + LONGBOW_RUN_TEST_CASE(Global, cpiForwarding_AddRoute_2); + LONGBOW_RUN_TEST_CASE(Global, cpiForwarding_AddRoute_3); + + LONGBOW_RUN_TEST_CASE(Global, cpiForwarding_AddRouteJsonTag); + LONGBOW_RUN_TEST_CASE(Global, cpiForwarding_AddRouteToSelf); + LONGBOW_RUN_TEST_CASE(Global, cpiForwarding_RemoveRoute); + LONGBOW_RUN_TEST_CASE(Global, cpiForwarding_RemoveRouteJsonTag); + LONGBOW_RUN_TEST_CASE(Global, cpiForwarding_RemoveRouteToSelf); + + LONGBOW_RUN_TEST_CASE(Global, cpiForwarding_RouteFromControlMessage); + + LONGBOW_RUN_TEST_CASE(Global, cpiForwarding_CreateRouteListRequest); + LONGBOW_RUN_TEST_CASE(Global, cpiForwarding_RouteListFromControlMessage); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + 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; +} + +/** + * Add route with all options + */ +LONGBOW_TEST_CASE(Global, cpiForwarding_AddRoute_1) +{ + // The JSON representation depends on the system sockaddr_in format, which + // varies platform to platform. +#if defined(__APPLE__) + char truth_format[] = "{\"CPI_REQUEST\":{\"SEQUENCE\":%" PRIu64 ",\"REGISTER\":{\"PREFIX\":\"ccnx:/howdie/stranger\",\"INTERFACE\":55,\"FLAGS\":0,\"NEXTHOP\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIAAAQDAgEAAAAAAAAAAA==\"},\"PROTOCOL\":\"STATIC\",\"ROUTETYPE\":\"LONGEST\",\"COST\":200,\"LIFETIME\":[3600,0]}}}"; +#elif defined(__linux__) + char truth_format[] = "{\"CPI_REQUEST\":{\"SEQUENCE\":%" PRIu64 ",\"REGISTER\":{\"PREFIX\":\"ccnx:/howdie/stranger\",\"INTERFACE\":55,\"FLAGS\":0,\"NEXTHOP\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAAAAQDAgEAAAAAAAAAAA==\"},\"PROTOCOL\":\"STATIC\",\"ROUTETYPE\":\"LONGEST\",\"COST\":200,\"LIFETIME\":[3600,0]}}}"; +#else + // Case 1033 + testUnimplemented("Platform not supported"); + return; +#endif + + char truth[1024]; + + CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger"); + unsigned ifidx = 55; + CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 }); + struct timeval lifetime = { 3600, 0 }; + unsigned cost = 200; + + CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost); + + CCNxControl *control = ccnxControl_CreateAddRouteRequest(route); + + // get its sequence number + uint64_t seqnum = cpi_GetSequenceNumber(control); + sprintf(truth, truth_format, seqnum); + + PARCJSON *test_json = ccnxControl_GetJson(control); + char *test = parcJSON_ToCompactString(test_json); + assertTrue(strcasecmp(truth, test) == 0, "Expected '%s', actual '%s'", truth, test); + parcMemory_Deallocate((void **) &test); + + ccnxControl_Release(&control); + cpiRouteEntry_Destroy(&route); + cpiAddress_Destroy(&nexthop); +} + +/** + * Add route without lifeitme + */ +LONGBOW_TEST_CASE(Global, cpiForwarding_AddRoute_2) +{ + // The JSON representation depends on the system sockaddr_in format, which + // varies platform to platform. +#if defined(__APPLE__) + char truth_format[] = "{\"CPI_REQUEST\":{\"SEQUENCE\":%" PRIu64 ",\"REGISTER\":{\"PREFIX\":\"ccnx:/howdie/stranger\",\"INTERFACE\":55,\"FLAGS\":0,\"NEXTHOP\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIAAAQDAgEAAAAAAAAAAA==\"},\"PROTOCOL\":\"STATIC\",\"ROUTETYPE\":\"LONGEST\",\"COST\":200}}}"; +#elif defined(__linux__) + char truth_format[] = "{\"CPI_REQUEST\":{\"SEQUENCE\":%" PRIu64 ",\"REGISTER\":{\"PREFIX\":\"ccnx:/howdie/stranger\",\"INTERFACE\":55,\"FLAGS\":0,\"NEXTHOP\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAAAAQDAgEAAAAAAAAAAA==\"},\"PROTOCOL\":\"STATIC\",\"ROUTETYPE\":\"LONGEST\",\"COST\":200}}}"; +#else + // Case 1033 + testUnimplemented("Platform not supported"); + return; +#endif + + char truth[1024]; + + CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger"); + unsigned ifidx = 55; + CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 }); + unsigned cost = 200; + + CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, cost); + CCNxControl *control = ccnxControl_CreateAddRouteRequest(route); + + // get its sequence number + uint64_t seqnum = cpi_GetSequenceNumber(control); + sprintf(truth, truth_format, seqnum); + + PARCJSON *test_json = ccnxControl_GetJson(control); + char *test = parcJSON_ToCompactString(test_json); + assertTrue(strcasecmp(truth, test) == 0, "Expected '%s', actual '%s'", truth, test); + parcMemory_Deallocate((void **) &test); + + ccnxControl_Release(&control); + cpiRouteEntry_Destroy(&route); + cpiAddress_Destroy(&nexthop); +} + +/** + * Add route without lifeitme or nexthop + */ +LONGBOW_TEST_CASE(Global, cpiForwarding_AddRoute_3) +{ + char truth_format[] = "{\"CPI_REQUEST\":{\"SEQUENCE\":%" PRIu64 ",\"REGISTER\":{\"PREFIX\":\"ccnx:/howdie/stranger\",\"INTERFACE\":55,\"FLAGS\":0,\"PROTOCOL\":\"STATIC\",\"ROUTETYPE\":\"LONGEST\",\"COST\":200}}}"; + char truth[1024]; + + CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger"); + unsigned ifidx = 55; + unsigned cost = 200; + + CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, NULL, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, cost); + CCNxControl *control = ccnxControl_CreateAddRouteRequest(route); + + // get its sequence number + uint64_t seqnum = cpi_GetSequenceNumber(control); + sprintf(truth, truth_format, seqnum); + + PARCJSON *test_json = ccnxControl_GetJson(control); + char *test = parcJSON_ToCompactString(test_json); + assertTrue(strcasecmp(truth, test) == 0, "Control message json does not match, expected '%s', got '%s'", truth, test); + parcMemory_Deallocate((void **) &test); + + ccnxControl_Release(&control); + cpiRouteEntry_Destroy(&route); +} + + +LONGBOW_TEST_CASE(Global, cpiForwarding_AddRouteJsonTag) +{ + const char *tag = cpiForwarding_AddRouteJsonTag(); + assertTrue(strcmp(tag, cpiRegister) == 0, "cpiForwarding_AddRouteJsonTag not using defined value %s", cpiRegister); +} + +LONGBOW_TEST_CASE(Global, cpiForwarding_AddRouteToSelf) +{ + char truth_format[] = "{\"CPI_REQUEST\":{\"SEQUENCE\":%" PRIu64 ",\"REGISTER\":{\"PREFIX\":\"ccnx:/howdie/stranger\",\"INTERFACE\":2147483647,\"FLAGS\":0,\"PROTOCOL\":\"LOCAL\",\"ROUTETYPE\":\"LONGEST\",\"COST\":0}}}"; + char truth[1024]; + + CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger"); + CCNxControl *control = ccnxControl_CreateAddRouteToSelfRequest(prefix); + uint64_t seqnum = cpi_GetSequenceNumber(control); + sprintf(truth, truth_format, seqnum); + + PARCJSON *test_json = ccnxControl_GetJson(control); + char *test = parcJSON_ToCompactString(test_json); + assertTrue(strcasecmp(truth, test) == 0, "Control message json does not match, expected '%s', got '%s'", truth, test); + parcMemory_Deallocate((void **) &test); + + ccnxControl_Release(&control); + ccnxName_Release(&prefix); +} + +LONGBOW_TEST_CASE(Global, cpiForwarding_RemoveRoute) +{ + char truth_format[] = "{\"CPI_REQUEST\":{\"SEQUENCE\":%" PRIu64 ",\"UNREGISTER\":{\"PREFIX\":\"ccnx:/howdie/stranger\",\"INTERFACE\":55,\"FLAGS\":0,\"PROTOCOL\":\"STATIC\",\"ROUTETYPE\":\"LONGEST\",\"COST\":200}}}"; + char truth[1024]; + + CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger"); + unsigned ifidx = 55; + unsigned cost = 200; + + CPIRouteEntry *route = + cpiRouteEntry_Create(prefix, ifidx, NULL, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, cost); + + CCNxControl *control = ccnxControl_CreateRemoveRouteRequest(route); + + // get its sequence number + uint64_t seqnum = cpi_GetSequenceNumber(control); + sprintf(truth, truth_format, seqnum); + + PARCJSON *test_json = ccnxControl_GetJson(control); + char *test = parcJSON_ToCompactString(test_json); + assertTrue(strcasecmp(truth, test) == 0, "Control message json does not match, expected '%s', got '%s'", truth, test); + parcMemory_Deallocate((void **) &test); + + ccnxControl_Release(&control); + cpiRouteEntry_Destroy(&route); +} + +LONGBOW_TEST_CASE(Global, cpiForwarding_RemoveRouteJsonTag) +{ + const char *tag = cpiForwarding_RemoveRouteJsonTag(); + assertTrue(strcmp(tag, cpiUnregister) == 0, "cpiForwarding_AddRouteJsonTag not using defined value %s", cpiUnregister); +} + +LONGBOW_TEST_CASE(Global, cpiForwarding_RemoveRouteToSelf) +{ + char truth_format[] = "{\"CPI_REQUEST\":{\"SEQUENCE\":%" PRIu64 ",\"UNREGISTER\":{\"PREFIX\":\"ccnx:/howdie/stranger\",\"INTERFACE\":2147483647,\"FLAGS\":0,\"PROTOCOL\":\"LOCAL\",\"ROUTETYPE\":\"LONGEST\",\"COST\":0}}}"; + char truth[1024]; + + CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger"); + CCNxControl *control = ccnxControl_CreateRemoveRouteToSelfRequest(prefix); + + uint64_t seqnum = cpi_GetSequenceNumber(control); + sprintf(truth, truth_format, seqnum); + + PARCJSON *test_json = ccnxControl_GetJson(control); + char *test = parcJSON_ToCompactString(test_json); + assertTrue(strcasecmp(truth, test) == 0, "Control message json does not match, expected '%s', got '%s'", truth, test); + parcMemory_Deallocate((void **) &test); + + ccnxControl_Release(&control); + ccnxName_Release(&prefix); +} + +LONGBOW_TEST_CASE(Global, cpiForwarding_RouteFromControlMessage) +{ + CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger"); + unsigned ifidx = 55; + CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 }); + unsigned cost = 200; + + CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, cost); + CCNxControl *control = ccnxControl_CreateAddRouteRequest(route); + + CPIRouteEntry *test_route = cpiForwarding_RouteFromControlMessage(control); + + assertTrue(cpiRouteEntry_Equals(route, test_route), + "messages not equa: expected %s got %s", + parcJSON_ToCompactString(cpiRouteEntry_ToJson(route)), + parcJSON_ToCompactString(cpiRouteEntry_ToJson(test_route))); + + cpiAddress_Destroy(&nexthop); + cpiRouteEntry_Destroy(&route); + cpiRouteEntry_Destroy(&test_route); + ccnxControl_Release(&control); +} + +LONGBOW_TEST_CASE(Global, cpiForwarding_CreateRouteListRequest) +{ + CCNxControl *control = ccnxControl_CreateRouteListRequest(); + + assertTrue(ccnxControl_IsCPI(control), "Control message not a CPI message"); + assertTrue(cpi_GetMessageOperation(control) == CPI_PREFIX_REGISTRATION_LIST, "Message not a prefix regisration list"); + + ccnxControl_Release(&control); +} + +LONGBOW_TEST_CASE(Global, cpiForwarding_RouteListFromControlMessage) +{ + CCNxControl *control = ccnxControl_CreateRouteListRequest(); + + CPIRouteEntryList *routeList = cpiRouteEntryList_Create(); + PARCJSON *json = cpiRouteEntryList_ToJson(routeList); + CCNxControl *response = cpi_CreateResponse(control, json); + parcJSON_Release(&json); + CPIRouteEntryList *test = cpiForwarding_RouteListFromControlMessage(response); + assertTrue(cpiRouteEntryList_Equals(routeList, test), "Route lists not equal"); + + ccnxControl_Release(&control); + ccnxControl_Release(&response); + cpiRouteEntryList_Destroy(&routeList); + cpiRouteEntryList_Destroy(&test); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_Forwarding); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Interface.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Interface.c new file mode 100644 index 00000000..b1c7b553 --- /dev/null +++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Interface.c @@ -0,0 +1,351 @@ +/* + * 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 "../cpi_Interface.c" +#include <LongBow/unit-test.h> + +#include <parc/algol/parc_SafeMemory.h> + + +LONGBOW_TEST_RUNNER(cpi_Interface) +{ + // 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); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(cpi_Interface) +{ + 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(cpi_Interface) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// ================================================================== + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, cpiInterface_Create_Destroy); + LONGBOW_RUN_TEST_CASE(Global, cpiInterface_AddAddress); + LONGBOW_RUN_TEST_CASE(Global, cpiInterface_GetAddresses); + LONGBOW_RUN_TEST_CASE(Global, cpiInterface_GetMtu); + LONGBOW_RUN_TEST_CASE(Global, cpiInterface_GetInterfaceIndex); + + LONGBOW_RUN_TEST_CASE(Global, cpiInterface_NameEquals_IsEqual); + LONGBOW_RUN_TEST_CASE(Global, cpiInterface_NameEquals_IsNotEqual); + + LONGBOW_RUN_TEST_CASE(Global, cpiInterface_ToJson); + LONGBOW_RUN_TEST_CASE(Global, cpiInterface_FromJson); + + LONGBOW_RUN_TEST_CASE(Global, cpiInterface_Equals_IsEqual); + LONGBOW_RUN_TEST_CASE(Global, cpiInterface_Equals_BothNull); + LONGBOW_RUN_TEST_CASE(Global, cpiInterface_Equals_OneNull); + LONGBOW_RUN_TEST_CASE(Global, cpiInterface_Equals_UnequalName); + LONGBOW_RUN_TEST_CASE(Global, cpiInterface_Equals_UnequalIndex); + LONGBOW_RUN_TEST_CASE(Global, cpiInterface_Equals_UnequalLoopback); + LONGBOW_RUN_TEST_CASE(Global, cpiInterface_Equals_UnequalMulticast); + LONGBOW_RUN_TEST_CASE(Global, cpiInterface_Equals_UnequalMTU); + LONGBOW_RUN_TEST_CASE(Global, cpiInterface_Equals_UnequalAddresses); + + LONGBOW_RUN_TEST_CASE(Global, cpiInterface_ToString); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + 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, cpiInterface_Create_Destroy) +{ + CPIInterface *iface = cpiInterface_Create("eth0", 1, true, false, 1500); + cpiInterface_Destroy(&iface); + + assertTrue(parcSafeMemory_ReportAllocation(STDOUT_FILENO) == 0, "Memory imbalance on create/destroy"); +} + +LONGBOW_TEST_CASE(Global, cpiInterface_AddAddress) +{ + CPIInterface *iface = cpiInterface_Create("eth0", 1, true, false, 1500); + + cpiInterface_AddAddress(iface, cpiAddress_CreateFromInterface(1)); + assertTrue(cpiAddressList_Length(iface->addressList) == 1, + "Incorrect address list length, expected %u got %zu", + 1, + cpiAddressList_Length(iface->addressList)); + + cpiInterface_AddAddress(iface, cpiAddress_CreateFromInterface(2)); + assertTrue(cpiAddressList_Length(iface->addressList) == 2, + "Incorrect address list length, expected %u got %zu", + 2, + cpiAddressList_Length(iface->addressList)); + + cpiInterface_Destroy(&iface); +} + +LONGBOW_TEST_CASE(Global, cpiInterface_GetAddresses) +{ + CPIInterface *iface = cpiInterface_Create("eth0", 1, true, false, 1500); + + cpiInterface_AddAddress(iface, cpiAddress_CreateFromInterface(1)); + cpiInterface_AddAddress(iface, cpiAddress_CreateFromInterface(2)); + + const CPIAddressList *list = cpiInterface_GetAddresses(iface); + assertTrue(cpiAddressList_Length(list) == 2, "Incorrect list size, expected %u got %zu", 2, cpiAddressList_Length(list)); + cpiInterface_Destroy(&iface); +} + +LONGBOW_TEST_CASE(Global, cpiInterface_GetMtu) +{ + CPIInterface *iface = cpiInterface_Create("eth0", 1, true, false, 1500); + + unsigned test = cpiInterface_GetMTU(iface); + assertTrue(test == 1500, "Wrong MTU expected 1500 got %u", test); + cpiInterface_Destroy(&iface); +} + +LONGBOW_TEST_CASE(Global, cpiInterface_GetInterfaceIndex) +{ + CPIInterface *iface = cpiInterface_Create("eth0", 1, true, false, 1500); + + cpiInterface_AddAddress(iface, cpiAddress_CreateFromInterface(1)); + cpiInterface_AddAddress(iface, cpiAddress_CreateFromInterface(2)); + + unsigned testvalue = cpiInterface_GetInterfaceIndex(iface); + + assertTrue(testvalue == 1, "Incorrect interfaceIndex, expected %u got %u", 1, testvalue); + cpiInterface_Destroy(&iface); +} + +LONGBOW_TEST_CASE(Global, cpiInterface_NameEquals_IsEqual) +{ + CPIInterface *iface = cpiInterface_Create("eth0", 1, true, false, 1500); + cpiInterface_AddAddress(iface, cpiAddress_CreateFromInterface(1)); + assertTrue(cpiInterface_NameEquals(iface, "eth0"), "name did not compare as equal"); + cpiInterface_Destroy(&iface); +} + +LONGBOW_TEST_CASE(Global, cpiInterface_NameEquals_IsNotEqual) +{ + CPIInterface *iface = cpiInterface_Create("eth0", 1, true, false, 1500); + cpiInterface_AddAddress(iface, cpiAddress_CreateFromInterface(1)); + assertFalse(cpiInterface_NameEquals(iface, "eth2"), "Unequal names compare as equal"); + cpiInterface_Destroy(&iface); +} + + +LONGBOW_TEST_CASE(Global, cpiInterface_ToJson) +{ + char truth[] = "{\"Interface\":{\"Name\":\"eth0\",\"Index\":1,\"Loopback\":\"true\",\"Multicast\":\"false\",\"MTU\":1500,\"Addrs\":[{\"ADDRESSTYPE\":\"IFACE\",\"DATA\":\"AAAAAQ==\"},{\"ADDRESSTYPE\":\"IFACE\",\"DATA\":\"AAAAAg==\"}]}}"; + + CPIInterface *iface = cpiInterface_Create("eth0", 1, true, false, 1500); + cpiInterface_AddAddress(iface, cpiAddress_CreateFromInterface(1)); + cpiInterface_AddAddress(iface, cpiAddress_CreateFromInterface(2)); + + PARCJSON *json = cpiInterface_ToJson(iface); + + char *str = parcJSON_ToCompactString(json); + assertTrue(strcmp(str, truth) == 0, "JSON mismatch, expected '%s' got '%s'", truth, str); + parcMemory_Deallocate((void **) &str); + parcJSON_Release(&json); + cpiInterface_Destroy(&iface); +} + +LONGBOW_TEST_CASE(Global, cpiInterface_FromJson) +{ + CPIInterface *iface = cpiInterface_Create("eth0", 1, true, false, 1500); + cpiInterface_AddAddress(iface, cpiAddress_CreateFromInterface(1)); + cpiInterface_AddAddress(iface, cpiAddress_CreateFromInterface(2)); + + PARCJSON *json = cpiInterface_ToJson(iface); + + CPIInterface *test_iface = cpiInterface_FromJson(json); + + assertTrue(cpiInterface_Equals(iface, test_iface), "Interface from json not equal to truth"); + + cpiInterface_Destroy(&test_iface); + cpiInterface_Destroy(&iface); + parcJSON_Release(&json); +} + +LONGBOW_TEST_CASE(Global, cpiInterface_Equals_IsEqual) +{ + CPIInterface *iface_a = cpiInterface_Create("eth0", 1, true, false, 1500); + cpiInterface_AddAddress(iface_a, cpiAddress_CreateFromInterface(1)); + cpiInterface_AddAddress(iface_a, cpiAddress_CreateFromInterface(2)); + + CPIInterface *iface_b = cpiInterface_Create("eth0", 1, true, false, 1500); + cpiInterface_AddAddress(iface_b, cpiAddress_CreateFromInterface(1)); + cpiInterface_AddAddress(iface_b, cpiAddress_CreateFromInterface(2)); + + assertTrue(cpiInterface_Equals(iface_a, iface_b), "Two equal interfaces did not compare equal"); + + cpiInterface_Destroy(&iface_b); + cpiInterface_Destroy(&iface_a); +} + +LONGBOW_TEST_CASE(Global, cpiInterface_Equals_BothNull) +{ + assertTrue(cpiInterface_Equals(NULL, NULL), "Two NULL interfaces did not compare equal"); +} + +LONGBOW_TEST_CASE(Global, cpiInterface_Equals_OneNull) +{ + CPIInterface *iface_a = cpiInterface_Create("eth0", 1, true, false, 1500); + cpiInterface_AddAddress(iface_a, cpiAddress_CreateFromInterface(1)); + cpiInterface_AddAddress(iface_a, cpiAddress_CreateFromInterface(2)); + + assertFalse(cpiInterface_Equals(iface_a, NULL), "One null one non-null interfaces compare equal"); + + cpiInterface_Destroy(&iface_a); +} + +LONGBOW_TEST_CASE(Global, cpiInterface_Equals_UnequalName) +{ + CPIInterface *iface_a = cpiInterface_Create("eth0", 1, true, false, 1500); + cpiInterface_AddAddress(iface_a, cpiAddress_CreateFromInterface(1)); + cpiInterface_AddAddress(iface_a, cpiAddress_CreateFromInterface(2)); + + CPIInterface *iface_b = cpiInterface_Create("eth1", 1, true, false, 1500); + cpiInterface_AddAddress(iface_b, cpiAddress_CreateFromInterface(1)); + cpiInterface_AddAddress(iface_b, cpiAddress_CreateFromInterface(2)); + + assertFalse(cpiInterface_Equals(iface_a, iface_b), "Two unequal interfaces compare equal"); + + cpiInterface_Destroy(&iface_b); + cpiInterface_Destroy(&iface_a); +} + +LONGBOW_TEST_CASE(Global, cpiInterface_Equals_UnequalIndex) +{ + CPIInterface *iface_a = cpiInterface_Create("eth0", 1, true, false, 1500); + cpiInterface_AddAddress(iface_a, cpiAddress_CreateFromInterface(1)); + cpiInterface_AddAddress(iface_a, cpiAddress_CreateFromInterface(2)); + + CPIInterface *iface_b = cpiInterface_Create("eth0", 2, true, false, 1500); + cpiInterface_AddAddress(iface_b, cpiAddress_CreateFromInterface(1)); + cpiInterface_AddAddress(iface_b, cpiAddress_CreateFromInterface(2)); + + assertFalse(cpiInterface_Equals(iface_a, iface_b), "Two unequal interfaces compare equal"); + + cpiInterface_Destroy(&iface_b); + cpiInterface_Destroy(&iface_a); +} + +LONGBOW_TEST_CASE(Global, cpiInterface_Equals_UnequalLoopback) +{ + CPIInterface *iface_a = cpiInterface_Create("eth0", 1, true, false, 1500); + cpiInterface_AddAddress(iface_a, cpiAddress_CreateFromInterface(1)); + cpiInterface_AddAddress(iface_a, cpiAddress_CreateFromInterface(2)); + + CPIInterface *iface_b = cpiInterface_Create("eth0", 1, false, false, 1500); + cpiInterface_AddAddress(iface_b, cpiAddress_CreateFromInterface(1)); + cpiInterface_AddAddress(iface_b, cpiAddress_CreateFromInterface(2)); + + assertFalse(cpiInterface_Equals(iface_a, iface_b), "Two unequal interfaces compare equal"); + + cpiInterface_Destroy(&iface_b); + cpiInterface_Destroy(&iface_a); +} + +LONGBOW_TEST_CASE(Global, cpiInterface_Equals_UnequalMulticast) +{ + CPIInterface *iface_a = cpiInterface_Create("eth0", 1, true, false, 1500); + cpiInterface_AddAddress(iface_a, cpiAddress_CreateFromInterface(1)); + cpiInterface_AddAddress(iface_a, cpiAddress_CreateFromInterface(2)); + + CPIInterface *iface_b = cpiInterface_Create("eth0", 1, true, true, 1500); + cpiInterface_AddAddress(iface_b, cpiAddress_CreateFromInterface(1)); + cpiInterface_AddAddress(iface_b, cpiAddress_CreateFromInterface(2)); + + assertFalse(cpiInterface_Equals(iface_a, iface_b), "Two unequal interfaces compare equal"); + + cpiInterface_Destroy(&iface_b); + cpiInterface_Destroy(&iface_a); +} + +LONGBOW_TEST_CASE(Global, cpiInterface_Equals_UnequalMTU) +{ + CPIInterface *iface_a = cpiInterface_Create("eth0", 1, true, false, 1500); + cpiInterface_AddAddress(iface_a, cpiAddress_CreateFromInterface(1)); + cpiInterface_AddAddress(iface_a, cpiAddress_CreateFromInterface(2)); + + CPIInterface *iface_b = cpiInterface_Create("eth0", 1, true, false, 9000); + cpiInterface_AddAddress(iface_b, cpiAddress_CreateFromInterface(1)); + cpiInterface_AddAddress(iface_b, cpiAddress_CreateFromInterface(2)); + + assertFalse(cpiInterface_Equals(iface_a, iface_b), "Two unequal interfaces compare equal"); + + cpiInterface_Destroy(&iface_b); + cpiInterface_Destroy(&iface_a); +} + +LONGBOW_TEST_CASE(Global, cpiInterface_Equals_UnequalAddresses) +{ + CPIInterface *iface_a = cpiInterface_Create("eth0", 1, true, false, 1500); + cpiInterface_AddAddress(iface_a, cpiAddress_CreateFromInterface(1)); + cpiInterface_AddAddress(iface_a, cpiAddress_CreateFromInterface(2)); + + CPIInterface *iface_b = cpiInterface_Create("eth0", 1, true, false, 1500); + cpiInterface_AddAddress(iface_b, cpiAddress_CreateFromInterface(3)); + cpiInterface_AddAddress(iface_b, cpiAddress_CreateFromInterface(2)); + + assertFalse(cpiInterface_Equals(iface_a, iface_b), "Two unequal interfaces compare equal"); + + cpiInterface_Destroy(&iface_b); + cpiInterface_Destroy(&iface_a); +} + +LONGBOW_TEST_CASE(Global, cpiInterface_ToString) +{ + CPIInterface *iface = cpiInterface_Create("eth0", 1, false, true, 1500); + cpiInterface_AddAddress(iface, cpiAddress_CreateFromInterface(1)); + + uint32_t beforeBalance = parcMemory_Outstanding(); + char *string = cpiInterface_ToString(iface); + parcMemory_Deallocate((void **) &string); + uint32_t afterBalance = parcMemory_Outstanding(); + cpiInterface_Destroy(&iface); + + assertTrue(beforeBalance == afterBalance, "Memory leak: off by %d allocations", (int) (afterBalance - beforeBalance)); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_Interface); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceEthernet.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceEthernet.c new file mode 100644 index 00000000..e96fc76f --- /dev/null +++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceEthernet.c @@ -0,0 +1,191 @@ +/* + * 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 "../cpi_InterfaceEthernet.c" +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> + + + +LONGBOW_TEST_RUNNER(cpi_InterfaceEthernet) +{ + // 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); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(cpi_InterfaceEthernet) +{ + 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(cpi_InterfaceEthernet) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceEthernet_Copy); + LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceEthernet_Create_Destroy); + LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceEthernet_GetAddresses); + LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceEthernet_GetIndex); + LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceEthernet_GetState); + LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceEthernet_ToJSON); + LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceEthernet_FromJSON); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + 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, cpiInterfaceEthernet_Copy) +{ + CPIAddress *addr = cpiAddress_CreateFromInterface(5); + CPIAddressList *list = cpiAddressList_Append(cpiAddressList_Create(), addr); + CPIInterfaceEthernet *ethernet = cpiInterfaceEthernet_Create(1, list); + + CPIInterfaceEthernet *copy = cpiInterfaceEthernet_Copy(ethernet); + + assertTrue(cpiInterfaceEthernet_GetIndex(copy) == cpiInterfaceEthernet_GetIndex(ethernet), + "ifidx did not match, expected %u got %u", + cpiInterfaceEthernet_GetIndex(ethernet), + cpiInterfaceEthernet_GetIndex(copy)); + + assertTrue(cpiInterfaceEthernet_GetState(copy) == cpiInterfaceEthernet_GetState(ethernet), + "states did not match, expected %d got %d", + cpiInterfaceEthernet_GetState(ethernet), + cpiInterfaceEthernet_GetState(copy)); + + assertTrue(cpiAddressList_Equals(cpiInterfaceEthernet_GetAddresses(copy), cpiInterfaceEthernet_GetAddresses(ethernet)), "did not get same addresses"); + + cpiInterfaceEthernet_Destroy(©); + cpiInterfaceEthernet_Destroy(ðernet); +} + +LONGBOW_TEST_CASE(Global, cpiInterfaceEthernet_Create_Destroy) +{ + CPIInterfaceEthernet *ethernet = cpiInterfaceEthernet_Create(1, cpiAddressList_Create()); + cpiInterfaceEthernet_Destroy(ðernet); + + assertTrue(parcMemory_Outstanding() == 0, "Imbalance after destroying"); +} + +LONGBOW_TEST_CASE(Global, cpiInterfaceEthernet_GetAddresses) +{ + CPIAddress *addr = cpiAddress_CreateFromInterface(5); + CPIAddressList *list = cpiAddressList_Append(cpiAddressList_Create(), addr); + CPIInterfaceEthernet *ethernet = cpiInterfaceEthernet_Create(1, list); + + const CPIAddressList *test = cpiInterfaceEthernet_GetAddresses(ethernet); + assertTrue(cpiAddressList_Equals(list, test), "Address lists did not match"); + + cpiInterfaceEthernet_Destroy(ðernet); +} + +LONGBOW_TEST_CASE(Global, cpiInterfaceEthernet_GetIndex) +{ + CPIAddress *addr = cpiAddress_CreateFromInterface(5); + CPIAddressList *list = cpiAddressList_Append(cpiAddressList_Create(), addr); + CPIInterfaceEthernet *ethernet = cpiInterfaceEthernet_Create(1, list); + + assertTrue(cpiInterfaceEthernet_GetIndex(ethernet) == 1, "ifidx did not match"); + + cpiInterfaceEthernet_Destroy(ðernet); +} + +LONGBOW_TEST_CASE(Global, cpiInterfaceEthernet_GetState) +{ + CPIAddress *addr = cpiAddress_CreateFromInterface(5); + CPIAddressList *list = cpiAddressList_Append(cpiAddressList_Create(), addr); + CPIInterfaceEthernet *ethernet = cpiInterfaceEthernet_Create(1, list); + + assertTrue(cpiInterfaceEthernet_GetState(ethernet) == CPI_IFACE_UNKNOWN, "state did not match"); + + cpiInterfaceEthernet_SetState(ethernet, CPI_IFACE_UP); + assertTrue(cpiInterfaceEthernet_GetState(ethernet) == CPI_IFACE_UP, "state did not match"); + + cpiInterfaceEthernet_SetState(ethernet, CPI_IFACE_DOWN); + assertTrue(cpiInterfaceEthernet_GetState(ethernet) == CPI_IFACE_DOWN, "state did not match"); + + cpiInterfaceEthernet_Destroy(ðernet); +} + +LONGBOW_TEST_CASE(Global, cpiInterfaceEthernet_ToJSON) +{ + char truth_json_str[] = "{\"ETHERNET\":{\"IFIDX\":1,\"ADDRS\":[{\"ADDRESSTYPE\":\"IFACE\",\"DATA\":\"AAAABQ==\"},{\"ADDRESSTYPE\":\"IFACE\",\"DATA\":\"AAAADw==\"}]}}"; + + CPIAddress *addr5 = cpiAddress_CreateFromInterface(5); + CPIAddress *addr15 = cpiAddress_CreateFromInterface(15); + CPIAddressList *list = cpiAddressList_Append(cpiAddressList_Append(cpiAddressList_Create(), addr5), addr15); + + CPIInterfaceEthernet *ethernet = cpiInterfaceEthernet_Create(1, list); + + PARCJSON *test_json = cpiInterfaceEthernet_ToJson(ethernet); + char *test_json_str = parcJSON_ToCompactString(test_json); + assertTrue(strcmp(truth_json_str, test_json_str) == 0, "JSON strings do not match"); + + parcMemory_Deallocate((void **) &test_json_str); + parcJSON_Release(&test_json); + cpiInterfaceEthernet_Destroy(ðernet); +} + +LONGBOW_TEST_CASE(Global, cpiInterfaceEthernet_FromJSON) +{ + char truth_json_str[] = "{\"ETHERNET\":{\"IFIDX\":1,\"STATE\":\"UP\",\"ADDRS\":[{\"ADDRESSTYPE\":\"IFACE\",\"DATA\":\"AAAABQ==\"},{\"ADDRESSTYPE\":\"IFACE\",\"DATA\":\"AAAADw==\"}]}}"; + + CPIAddress *addr5 = cpiAddress_CreateFromInterface(5); + CPIAddress *addr15 = cpiAddress_CreateFromInterface(15); + CPIAddressList *list = cpiAddressList_Append(cpiAddressList_Append(cpiAddressList_Create(), addr5), addr15); + + CPIInterfaceEthernet *truth = cpiInterfaceEthernet_Create(1, list); + cpiInterfaceEthernet_SetState(truth, CPI_IFACE_UP); + + PARCJSON *json = parcJSON_ParseString(truth_json_str); + + CPIInterfaceEthernet *test = cpiInterfaceEthernet_CreateFromJson(json); + assertTrue(cpiInterfaceEthernet_Equals(truth, test), "Ethernet interfaces do not match"); + + parcJSON_Release(&json); + cpiInterfaceEthernet_Destroy(&truth); + cpiInterfaceEthernet_Destroy(&test); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_InterfaceEthernet); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceGeneric.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceGeneric.c new file mode 100644 index 00000000..d427bb78 --- /dev/null +++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceGeneric.c @@ -0,0 +1,157 @@ +/* + * 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 "../cpi_InterfaceGeneric.c" +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> + + +LONGBOW_TEST_RUNNER(cpi_InterfaceGeneric) +{ + // 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); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(cpi_InterfaceGeneric) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(cpi_InterfaceGeneric) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceGeneric_Copy); + LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceGeneric_Create_Destroy); + LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceGeneric_GetAddresses); + LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceGeneric_GetIndex); + LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceGeneric_GetState); + LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceGeneric_BuildString); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + 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, cpiInterfaceGeneric_Copy) +{ + CPIAddress *addr = cpiAddress_CreateFromInterface(5); + CPIAddressList *list = cpiAddressList_Append(cpiAddressList_Create(), addr); + CPIInterfaceGeneric *Generic = cpiInterfaceGeneric_Create(1, list); + + CPIInterfaceGeneric *copy = cpiInterfaceGeneric_Copy(Generic); + + assertTrue(copy->ifidx == Generic->ifidx, "ifidx did not match, expected %u got %u", Generic->ifidx, copy->ifidx); + assertTrue(copy->state == Generic->state, "states did not match, expected %d got %d", Generic->state, copy->state); + assertTrue(cpiAddressList_Equals(copy->addresses, Generic->addresses), "did not get same addresses"); + + cpiInterfaceGeneric_Destroy(©); + cpiInterfaceGeneric_Destroy(&Generic); +} + +LONGBOW_TEST_CASE(Global, cpiInterfaceGeneric_Create_Destroy) +{ + CPIInterfaceGeneric *Generic = cpiInterfaceGeneric_Create(1, cpiAddressList_Create()); + cpiInterfaceGeneric_Destroy(&Generic); + + assertTrue(parcMemory_Outstanding() == 0, "Imbalance after destroying"); +} + +LONGBOW_TEST_CASE(Global, cpiInterfaceGeneric_GetAddresses) +{ + CPIAddress *addr = cpiAddress_CreateFromInterface(5); + CPIAddressList *list = cpiAddressList_Append(cpiAddressList_Create(), addr); + CPIInterfaceGeneric *Generic = cpiInterfaceGeneric_Create(1, list); + + const CPIAddressList *test = cpiInterfaceGeneric_GetAddresses(Generic); + assertTrue(cpiAddressList_Equals(list, test), "Address lists did not match"); + + cpiInterfaceGeneric_Destroy(&Generic); +} + +LONGBOW_TEST_CASE(Global, cpiInterfaceGeneric_GetIndex) +{ + CPIAddress *addr = cpiAddress_CreateFromInterface(5); + CPIAddressList *list = cpiAddressList_Append(cpiAddressList_Create(), addr); + CPIInterfaceGeneric *Generic = cpiInterfaceGeneric_Create(1, list); + + assertTrue(cpiInterfaceGeneric_GetIndex(Generic) == 1, "ifidx did not match"); + + cpiInterfaceGeneric_Destroy(&Generic); +} + +LONGBOW_TEST_CASE(Global, cpiInterfaceGeneric_GetState) +{ + CPIAddress *addr = cpiAddress_CreateFromInterface(5); + CPIAddressList *list = cpiAddressList_Append(cpiAddressList_Create(), addr); + CPIInterfaceGeneric *Generic = cpiInterfaceGeneric_Create(1, list); + + assertTrue(cpiInterfaceGeneric_GetState(Generic) == CPI_IFACE_UNKNOWN, "state did not match"); + + cpiInterfaceGeneric_SetState(Generic, CPI_IFACE_UP); + assertTrue(cpiInterfaceGeneric_GetState(Generic) == CPI_IFACE_UP, "state did not match"); + + cpiInterfaceGeneric_SetState(Generic, CPI_IFACE_DOWN); + assertTrue(cpiInterfaceGeneric_GetState(Generic) == CPI_IFACE_DOWN, "state did not match"); + + cpiInterfaceGeneric_Destroy(&Generic); +} + +LONGBOW_TEST_CASE(Global, cpiInterfaceGeneric_BuildString) +{ + CPIAddressList *addrs = cpiAddressList_Create(); + cpiAddressList_Append(addrs, cpiAddress_CreateFromInterface(1)); + cpiAddressList_Append(addrs, cpiAddress_CreateFromInterface(2)); + + CPIInterfaceGeneric *generic = cpiInterfaceGeneric_Create(1, addrs); + + uint32_t beforeBalance = parcMemory_Outstanding(); + PARCBufferComposer *composer = cpiInterfaceGeneric_BuildString(generic, parcBufferComposer_Create()); + parcBufferComposer_Release(&composer); + uint32_t afterBalance = parcMemory_Outstanding(); + + cpiInterfaceGeneric_Destroy(&generic); + + assertTrue(beforeBalance == afterBalance, "Memory leak in BuildString: %d", (int) (afterBalance - beforeBalance)); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_InterfaceGeneric); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceIPTunnel.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceIPTunnel.c new file mode 100644 index 00000000..20a5cfc7 --- /dev/null +++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceIPTunnel.c @@ -0,0 +1,224 @@ +/* + * 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 "../cpi_InterfaceIPTunnel.c" +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> + + +LONGBOW_TEST_RUNNER(cpi_InterfaceIPTunnel) +{ + // 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); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(cpi_InterfaceIPTunnel) +{ + 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(cpi_InterfaceIPTunnel) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceIPTunnel_Copy); + LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceIPTunnel_Create_Destroy); + LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceIPTunnel_GetAddresses); + LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceIPTunnel_GetIndex); + LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceIPTunnel_GetState); + LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceIPTunnel_ToJSON); + LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceIPTunnel_FromJSON); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + 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, cpiInterfaceIPTunnel_Copy) +{ + CPIAddress *src = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 })); + CPIAddress *dst = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x05060708 })); + CPIInterfaceIPTunnel *iptun = cpiInterfaceIPTunnel_Create(1, src, dst, IPTUN_TCP, "tun0"); + + CPIInterfaceIPTunnel *copy = cpiInterfaceIPTunnel_Copy(iptun); + + assertTrue(cpiInterfaceIPTunnel_GetIndex(copy) == cpiInterfaceIPTunnel_GetIndex(iptun), + "ifidx did not match, expected %u got %u", + cpiInterfaceIPTunnel_GetIndex(iptun), + cpiInterfaceIPTunnel_GetIndex(copy)); + + assertTrue(cpiInterfaceIPTunnel_GetState(copy) == cpiInterfaceIPTunnel_GetState(iptun), + "states did not match, expected %d got %d", + cpiInterfaceIPTunnel_GetState(iptun), + cpiInterfaceIPTunnel_GetState(copy)); + + assertTrue(cpiAddress_Equals(cpiInterfaceIPTunnel_GetSourceAddress(copy), cpiInterfaceIPTunnel_GetSourceAddress(iptun)), + "did not get same source address"); + assertTrue(cpiAddress_Equals(cpiInterfaceIPTunnel_GetDestinationAddress(copy), cpiInterfaceIPTunnel_GetDestinationAddress(iptun)), + "did not get same destination address"); + + assertTrue(cpiInterfaceIPTunnel_GetTunnelType(copy) == cpiInterfaceIPTunnel_GetTunnelType(iptun), + "did not get same tunnel types!"); + + assertNotNull(copy->symbolic, "Copy has null symbolic name"); + assertTrue(strcmp(iptun->symbolic, copy->symbolic) == 0, "symbolics name wrong expected '%s' got '%s'", + iptun->symbolic, copy->symbolic); + + cpiInterfaceIPTunnel_Release(©); + cpiInterfaceIPTunnel_Release(&iptun); +} + +LONGBOW_TEST_CASE(Global, cpiInterfaceIPTunnel_Create_Destroy) +{ + CPIAddress *src = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 })); + CPIAddress *dst = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x05060708 })); + CPIInterfaceIPTunnel *iptun = cpiInterfaceIPTunnel_Create(1, src, dst, IPTUN_GRE, "tun0"); + cpiInterfaceIPTunnel_Release(&iptun); + + assertTrue(parcMemory_Outstanding() == 0, "Imbalance after destroying"); +} + +LONGBOW_TEST_CASE(Global, cpiInterfaceIPTunnel_GetAddresses) +{ + CPIAddress *src = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 })); + CPIAddress *dst = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x05060708 })); + CPIInterfaceIPTunnel *iptun = cpiInterfaceIPTunnel_Create(1, src, dst, IPTUN_TCP, "tun0"); + + const CPIAddress *test; + + test = cpiInterfaceIPTunnel_GetSourceAddress(iptun); + assertTrue(cpiAddress_Equals(src, test), "Address lists did not match"); + + test = cpiInterfaceIPTunnel_GetDestinationAddress(iptun); + assertTrue(cpiAddress_Equals(dst, test), "Address lists did not match"); + + cpiInterfaceIPTunnel_Release(&iptun); +} + +LONGBOW_TEST_CASE(Global, cpiInterfaceIPTunnel_GetIndex) +{ + CPIAddress *src = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 })); + CPIAddress *dst = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x05060708 })); + CPIInterfaceIPTunnel *iptun = cpiInterfaceIPTunnel_Create(1, src, dst, IPTUN_TCP, "tun0"); + + assertTrue(cpiInterfaceIPTunnel_GetIndex(iptun) == 1, "ifidx did not match"); + + cpiInterfaceIPTunnel_Release(&iptun); +} + +LONGBOW_TEST_CASE(Global, cpiInterfaceIPTunnel_GetState) +{ + CPIAddress *src = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 })); + CPIAddress *dst = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x05060708 })); + CPIInterfaceIPTunnel *iptun = cpiInterfaceIPTunnel_Create(1, src, dst, IPTUN_TCP, "tun0"); + + assertTrue(cpiInterfaceIPTunnel_GetState(iptun) == CPI_IFACE_UNKNOWN, "state did not match"); + + cpiInterfaceIPTunnel_SetState(iptun, CPI_IFACE_UP); + assertTrue(cpiInterfaceIPTunnel_GetState(iptun) == CPI_IFACE_UP, "state did not match"); + + cpiInterfaceIPTunnel_SetState(iptun, CPI_IFACE_DOWN); + assertTrue(cpiInterfaceIPTunnel_GetState(iptun) == CPI_IFACE_DOWN, "state did not match"); + + cpiInterfaceIPTunnel_Release(&iptun); +} + +LONGBOW_TEST_CASE(Global, cpiInterfaceIPTunnel_ToJSON) +{ + // The JSON representation depends on the system sockaddr_in format, which + // varies platform to platform. +#if defined(__APPLE__) + char *expected = "{\"TUNNEL\":{\"IFIDX\":1,\"SYMBOLIC\":\"tun0\",\"TUNTYPE\":\"TCP\",\"SRC\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIAAAQDAgEAAAAAAAAAAA==\"},\"DST\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIAAAgHBgUAAAAAAAAAAA==\"}}}"; +#elif defined(__linux__) + char *expected = "{\"TUNNEL\":{\"IFIDX\":1,\"SYMBOLIC\":\"tun0\",\"TUNTYPE\":\"TCP\",\"SRC\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAAAAQDAgEAAAAAAAAAAA==\"},\"DST\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAAAAgHBgUAAAAAAAAAAA==\"}}}"; +#else + // Case 1033 + testUnimplemented("Platform not supported"); + return; +#endif + + CPIAddress *src = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 })); + CPIAddress *dst = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x05060708 })); + CPIInterfaceIPTunnel *iptun = cpiInterfaceIPTunnel_Create(1, src, dst, IPTUN_TCP, "tun0"); + + PARCJSON *test_json = cpiInterfaceIPTunnel_ToJson(iptun); + + char *actual = parcJSON_ToCompactString(test_json); + assertEqualStrings(expected, actual); + + parcMemory_Deallocate((void **) &actual); + parcJSON_Release(&test_json); + cpiInterfaceIPTunnel_Release(&iptun); +} + +LONGBOW_TEST_CASE(Global, cpiInterfaceIPTunnel_FromJSON) +{ + // The JSON representation depends on the system sockaddr_in format, which + // varies platform to platform. +#if defined(__APPLE__) + char truth_json_str[] = "{\"TUNNEL\":{\"IFIDX\":1,\"SYMBOLIC\":\"tun0\",\"STATE\":\"UP\",\"TUNTYPE\":\"TCP\",\"SRC\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIAAAQDAgEAAAAAAAAAAA==\"},\"DST\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIAAAgHBgUAAAAAAAAAAA==\"}}}"; +#elif defined(__linux__) + char truth_json_str[] = "{\"TUNNEL\":{\"IFIDX\":1,\"SYMBOLIC\":\"tun0\",\"STATE\":\"UP\",\"TUNTYPE\":\"TCP\",\"SRC\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAAAAQDAgEAAAAAAAAAAA==\"},\"DST\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAAAAgHBgUAAAAAAAAAAA==\"}}}"; +#else + // Case 1033 + testUnimplemented("Platform not supported"); + return; +#endif + + + CPIAddress *src = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 })); + CPIAddress *dst = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_addr.s_addr = 0x05060708 })); + CPIInterfaceIPTunnel *truth = cpiInterfaceIPTunnel_Create(1, src, dst, IPTUN_TCP, "tun0"); + cpiInterfaceIPTunnel_SetState(truth, CPI_IFACE_UP); + + PARCJSON *json = parcJSON_ParseString(truth_json_str); + + CPIInterfaceIPTunnel *test = cpiInterfaceIPTunnel_CreateFromJson(json); + assertTrue(cpiInterfaceIPTunnel_Equals(truth, test), "IPTunnel interfaces do not match"); + + parcJSON_Release(&json); + cpiInterfaceIPTunnel_Release(&truth); + cpiInterfaceIPTunnel_Release(&test); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_InterfaceIPTunnel); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceIPTunnelList.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceIPTunnelList.c new file mode 100644 index 00000000..956ac4c3 --- /dev/null +++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceIPTunnelList.c @@ -0,0 +1,181 @@ +/* + * 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 "../cpi_InterfaceIPTunnelList.c" +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> + + +LONGBOW_TEST_RUNNER(cpi_InterfaceIPTunnelList) +{ + // 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); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(cpi_InterfaceIPTunnelList) +{ + 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(cpi_InterfaceIPTunnelList) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceIPTunnelList_Append); + LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceIPTunnelList_Create_Destroy); + LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceIPTunnelList_FromJson); + LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceIPTunnelList_Equals); + LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceIPTunnelList_ToJson); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + 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; +} + +static CPIInterfaceIPTunnel * +createTunnelObject(unsigned ifidx, int s_addr, uint16_t s_port, int d_addr, uint16_t d_port) +{ + return cpiInterfaceIPTunnel_Create(ifidx, + cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_family = PF_INET, .sin_addr.s_addr = s_addr, .sin_port = s_port }), + cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_family = PF_INET, .sin_addr.s_addr = d_addr, .sin_port = d_port }), + IPTUN_TCP, "tun0"); +} + +LONGBOW_TEST_CASE(Global, cpiInterfaceIPTunnelList_Append) +{ + CPIInterfaceIPTunnelList *list = cpiInterfaceIPTunnelList_Create(); + cpiInterfaceIPTunnelList_Append(list, createTunnelObject(1, 2, 3, 4, 5)); + + assertTrue(parcArrayList_Size(list->listOfTunnels) == 1, "got wrong size, expected %u got %zu", 1, parcArrayList_Size(list->listOfTunnels)); + + cpiInterfaceIPTunnelList_Destroy(&list); +} + +LONGBOW_TEST_CASE(Global, cpiInterfaceIPTunnelList_Create_Destroy) +{ + CPIInterfaceIPTunnelList *list = cpiInterfaceIPTunnelList_Create(); + cpiInterfaceIPTunnelList_Destroy(&list); + assertTrue(parcMemory_Outstanding() == 0, "Memory imbalance after create/destroy"); +} + +LONGBOW_TEST_CASE(Global, cpiInterfaceIPTunnelList_FromJson) +{ + // The JSON representation depends on the system sockaddr_in format, which + // varies platform to platform. +#if defined(__APPLE__) + char truth_string[] = "{\"TunnelList\":[{\"TUNNEL\":{\"IFIDX\":1,\"SYMBOLIC\":\"tun0\",\"TUNTYPE\":\"TCP\",\"SRC\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIDAAIAAAAAAAAAAAAAAA==\"},\"DST\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIFAAQAAAAAAAAAAAAAAA==\"}}}]}"; +#elif defined(__linux__) + char truth_string[] = "{\"TunnelList\":[{\"TUNNEL\":{\"IFIDX\":1,\"SYMBOLIC\":\"tun0\",\"TUNTYPE\":\"TCP\",\"SRC\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgADAAIAAAAAAAAAAAAAAA==\"},\"DST\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAFAAQAAAAAAAAAAAAAAA==\"}}}]}"; +#else + // Case 1033 + testUnimplemented("Platform not supported"); + return; +#endif + + + CPIInterfaceIPTunnelList *truth_list = cpiInterfaceIPTunnelList_Create(); + cpiInterfaceIPTunnelList_Append(truth_list, createTunnelObject(1, 2, 3, 4, 5)); + + PARCJSON *truth_json = parcJSON_ParseString(truth_string); + CPIInterfaceIPTunnelList *test_list = cpiInterfaceIPTunnelList_FromJson(truth_json); + + assertTrue(cpiInterfaceIPTunnelList_Equals(truth_list, test_list), "Lists do not match"); + + cpiInterfaceIPTunnelList_Destroy(&test_list); + parcJSON_Release(&truth_json); + cpiInterfaceIPTunnelList_Destroy(&truth_list); +} + +LONGBOW_TEST_CASE(Global, cpiInterfaceIPTunnelList_Equals) +{ + CPIInterfaceIPTunnelList *list_a = cpiInterfaceIPTunnelList_Create(); + cpiInterfaceIPTunnelList_Append(list_a, createTunnelObject(1, 2, 3, 4, 5)); + + CPIInterfaceIPTunnelList *list_b = cpiInterfaceIPTunnelList_Create(); + cpiInterfaceIPTunnelList_Append(list_b, createTunnelObject(1, 2, 3, 4, 5)); + + CPIInterfaceIPTunnelList *list_c = cpiInterfaceIPTunnelList_Create(); + cpiInterfaceIPTunnelList_Append(list_c, createTunnelObject(1, 2, 3, 4, 5)); + + CPIInterfaceIPTunnelList *unequal = cpiInterfaceIPTunnelList_Create(); + cpiInterfaceIPTunnelList_Append(unequal, createTunnelObject(99, 2, 3, 4, 5)); + cpiInterfaceIPTunnelList_Append(unequal, createTunnelObject(1, 99, 3, 4, 5)); + cpiInterfaceIPTunnelList_Append(unequal, createTunnelObject(1, 2, 99, 4, 5)); + cpiInterfaceIPTunnelList_Append(unequal, createTunnelObject(1, 2, 3, 99, 5)); + cpiInterfaceIPTunnelList_Append(unequal, createTunnelObject(1, 2, 3, 4, 99)); + + assertEqualsContract(cpiInterfaceIPTunnelList_Equals, list_a, list_b, list_c, unequal); + + cpiInterfaceIPTunnelList_Destroy(&unequal); + cpiInterfaceIPTunnelList_Destroy(&list_a); + cpiInterfaceIPTunnelList_Destroy(&list_b); + cpiInterfaceIPTunnelList_Destroy(&list_c); +} + +LONGBOW_TEST_CASE(Global, cpiInterfaceIPTunnelList_ToJson) +{ + // The JSON representation depends on the system sockaddr_in format, which + // varies platform to platform. +#if defined(__APPLE__) + char truth_string[] = "{\"TunnelList\":[{\"TUNNEL\":{\"IFIDX\":1,\"SYMBOLIC\":\"tun0\",\"TUNTYPE\":\"TCP\",\"SRC\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIDAAIAAAAAAAAAAAAAAA==\"},\"DST\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIFAAQAAAAAAAAAAAAAAA==\"}}}]}"; +#elif defined(__linux__) + char truth_string[] = "{\"TunnelList\":[{\"TUNNEL\":{\"IFIDX\":1,\"SYMBOLIC\":\"tun0\",\"TUNTYPE\":\"TCP\",\"SRC\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgADAAIAAAAAAAAAAAAAAA==\"},\"DST\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAFAAQAAAAAAAAAAAAAAA==\"}}}]}"; +#else + // Case 1033 + testUnimplemented("Platform not supported"); + return; +#endif + + CPIInterfaceIPTunnelList *list = cpiInterfaceIPTunnelList_Create(); + cpiInterfaceIPTunnelList_Append(list, createTunnelObject(1, 2, 3, 4, 5)); + + PARCJSON *json = cpiInterfaceIPTunnelList_ToJson(list); + char *test = parcJSON_ToCompactString(json); + assertTrue(strcmp(truth_string, test) == 0, "Got wrong JSON.\nexpected: %s\ngot %s\n", truth_string, test); + parcMemory_Deallocate((void **) &test); + + parcJSON_Release(&json); + cpiInterfaceIPTunnelList_Destroy(&list); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_InterfaceIPTunnelList); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceSet.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceSet.c new file mode 100644 index 00000000..d87149bf --- /dev/null +++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceSet.c @@ -0,0 +1,243 @@ +/* + * 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 "../cpi_InterfaceSet.c" +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> + + + +LONGBOW_TEST_RUNNER(cpi_InterfaceSet) +{ + // 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); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(cpi_InterfaceSet) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(cpi_InterfaceSet) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceSet_Add_Single); + LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceSet_Add_TwoUnique); + LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceSet_Add_TwoSame); + + LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceSet_Create_Destroy); + LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceSet_FromJson); + LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceSet_GetByInterfaceIndex); + LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceSet_GetByName); + LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceSet_GetByOrdinalIndex); + LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceSet_Length); + LONGBOW_RUN_TEST_CASE(Global, cpiInterfaceSet_ToJson); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + 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, cpiInterfaceSet_Add_Single) +{ + CPIInterfaceSet *set = cpiInterfaceSet_Create(); + + CPIInterface *iface = cpiInterface_Create("eth0", 11, false, true, 1500); + bool success = cpiInterfaceSet_Add(set, iface); + assertTrue(success, "Adding one interface did not succeed"); + assertTrue(parcArrayList_Size(set->listOfInterfaces) == 1, "List wrong size, expected %u got %zu", 1, parcArrayList_Size(set->listOfInterfaces)); + cpiInterfaceSet_Destroy(&set); +} + +LONGBOW_TEST_CASE(Global, cpiInterfaceSet_Add_TwoUnique) +{ + CPIInterfaceSet *set = cpiInterfaceSet_Create(); + + CPIInterface *iface0 = cpiInterface_Create("eth0", 11, false, true, 1500); + bool success = cpiInterfaceSet_Add(set, iface0); + assertTrue(success, "Adding one interface did not succeed"); + + CPIInterface *iface1 = cpiInterface_Create("eth1", 12, false, true, 1500); + success = cpiInterfaceSet_Add(set, iface1); + assertTrue(success, "Adding second interface did not succeed"); + + assertTrue(parcArrayList_Size(set->listOfInterfaces) == 2, "List wrong size, expected %u got %zu", 2, parcArrayList_Size(set->listOfInterfaces)); + cpiInterfaceSet_Destroy(&set); +} + +LONGBOW_TEST_CASE(Global, cpiInterfaceSet_Add_TwoSame) +{ + CPIInterfaceSet *set = cpiInterfaceSet_Create(); + + CPIInterface *iface0 = cpiInterface_Create("eth0", 11, false, true, 1500); + bool success = cpiInterfaceSet_Add(set, iface0); + assertTrue(success, "Adding one interface did not succeed"); + + CPIInterface *iface1 = cpiInterface_Create("eth0", 11, false, true, 1500); + success = cpiInterfaceSet_Add(set, iface1); + assertFalse(success, "Adding second interface duplicate interface should have failed"); + cpiInterface_Destroy(&iface1); + + assertTrue(parcArrayList_Size(set->listOfInterfaces) == 1, "List wrong size, expected %u got %zu", 1, parcArrayList_Size(set->listOfInterfaces)); + cpiInterfaceSet_Destroy(&set); +} + + +LONGBOW_TEST_CASE(Global, cpiInterfaceSet_Create_Destroy) +{ + CPIInterfaceSet *set = cpiInterfaceSet_Create(); + cpiInterfaceSet_Destroy(&set); + assertTrue(parcMemory_Outstanding() == 0, "Memory imbalance after create/destroy"); +} + +LONGBOW_TEST_CASE(Global, cpiInterfaceSet_GetByInterfaceIndex) +{ + CPIInterfaceSet *set = cpiInterfaceSet_Create(); + + CPIInterface *iface0 = cpiInterface_Create("eth0", 11, false, true, 1500); + cpiInterfaceSet_Add(set, iface0); + + CPIInterface *iface1 = cpiInterface_Create("eth1", 12, false, true, 1500); + cpiInterfaceSet_Add(set, iface1); + + CPIInterface *test = cpiInterfaceSet_GetByInterfaceIndex(set, 11); + + assertTrue(cpiInterface_Equals(test, iface0), "Did not get back right interface"); + + cpiInterfaceSet_Destroy(&set); +} + +LONGBOW_TEST_CASE(Global, cpiInterfaceSet_GetByName) +{ + CPIInterfaceSet *set = cpiInterfaceSet_Create(); + + CPIInterface *iface0 = cpiInterface_Create("eth0", 11, false, true, 1500); + cpiInterfaceSet_Add(set, iface0); + + CPIInterface *iface1 = cpiInterface_Create("eth1", 12, false, true, 1500); + cpiInterfaceSet_Add(set, iface1); + + CPIInterface *test = cpiInterfaceSet_GetByName(set, "eth0"); + + assertTrue(cpiInterface_Equals(test, iface0), "Did not get back right interface"); + + cpiInterfaceSet_Destroy(&set); +} + +LONGBOW_TEST_CASE(Global, cpiInterfaceSet_GetByOrdinalIndex) +{ + CPIInterfaceSet *set = cpiInterfaceSet_Create(); + + CPIInterface *iface0 = cpiInterface_Create("eth0", 11, false, true, 1500); + cpiInterfaceSet_Add(set, iface0); + + CPIInterface *iface1 = cpiInterface_Create("eth1", 12, false, true, 1500); + cpiInterfaceSet_Add(set, iface1); + + CPIInterface *test = cpiInterfaceSet_GetByOrdinalIndex(set, 0); + + assertTrue(cpiInterface_Equals(test, iface0), "Did not get back right interface"); + + cpiInterfaceSet_Destroy(&set); +} + +LONGBOW_TEST_CASE(Global, cpiInterfaceSet_Length) +{ + CPIInterfaceSet *set = cpiInterfaceSet_Create(); + + CPIInterface *iface0 = cpiInterface_Create("eth0", 11, false, true, 1500); + cpiInterfaceSet_Add(set, iface0); + + CPIInterface *iface1 = cpiInterface_Create("eth1", 12, false, true, 1500); + cpiInterfaceSet_Add(set, iface1); + + size_t length = cpiInterfaceSet_Length(set); + + assertTrue(length == 2, "Wrong length, expected %u got %zu", 2, length); + + cpiInterfaceSet_Destroy(&set); +} + +LONGBOW_TEST_CASE(Global, cpiInterfaceSet_ToJson) +{ + char truth[] = "{\"Interfaces\":[{\"Interface\":{\"Name\":\"eth0\",\"Index\":11,\"Loopback\":\"false\",\"Multicast\":\"true\",\"MTU\":1500,\"Addrs\":[]}},{\"Interface\":{\"Name\":\"eth1\",\"Index\":12,\"Loopback\":\"false\",\"Multicast\":\"true\",\"MTU\":1500,\"Addrs\":[]}}]}"; + + CPIInterfaceSet *set = cpiInterfaceSet_Create(); + + CPIInterface *iface0 = cpiInterface_Create("eth0", 11, false, true, 1500); + cpiInterfaceSet_Add(set, iface0); + + CPIInterface *iface1 = cpiInterface_Create("eth1", 12, false, true, 1500); + cpiInterfaceSet_Add(set, iface1); + + PARCJSON *json = cpiInterfaceSet_ToJson(set); + char *str = parcJSON_ToCompactString(json); + assertTrue(strcasecmp(truth, str) == 0, "Json wrong, expected '%s' got '%s'", truth, str); + parcMemory_Deallocate((void **) &str); + + parcJSON_Release(&json); + cpiInterfaceSet_Destroy(&set); +} + +LONGBOW_TEST_CASE(Global, cpiInterfaceSet_FromJson) +{ + CPIInterfaceSet *set = cpiInterfaceSet_Create(); + + CPIInterface *iface0 = cpiInterface_Create("eth0", 11, false, true, 1500); + cpiInterfaceSet_Add(set, iface0); + + CPIInterface *iface1 = cpiInterface_Create("eth1", 12, false, true, 1500); + cpiInterfaceSet_Add(set, iface1); + + PARCJSON *json = cpiInterfaceSet_ToJson(set); + + CPIInterfaceSet *test_set = cpiInterfaceSet_FromJson(json); + + assertTrue(cpiInterfaceSet_Equals(set, test_set), "CPIInterfaceSet from json did not equal truth set"); + + parcJSON_Release(&json); + cpiInterfaceSet_Destroy(&set); + cpiInterfaceSet_Destroy(&test_set); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_InterfaceSet); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceTypes.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceTypes.c new file mode 100644 index 00000000..a207eecd --- /dev/null +++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_InterfaceTypes.c @@ -0,0 +1,91 @@ +/* + * 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 "../cpi_InterfaceType.c" +#include <LongBow/unit-test.h> + +#include <parc/algol/parc_SafeMemory.h> + + + +LONGBOW_TEST_RUNNER(cpi_InterfaceTypes) +{ + // 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(cpi_InterfaceTypes) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(cpi_InterfaceTypes) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + 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_FIXTURE(Local) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + 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; +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_InterfaceTypes); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Listener.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Listener.c new file mode 100644 index 00000000..5bd5a534 --- /dev/null +++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Listener.c @@ -0,0 +1,384 @@ +/* + * 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 "../cpi_Listener.c" +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> +#include <arpa/inet.h> +#include <errno.h> + +typedef struct test_data { + CPIListener *listener; + + // the truth values of the connection + uint8_t macArray[6]; + CPIAddress *macAddress; + uint16_t ethertype; + char ifname[16]; + char symbolic[16]; +} TestData; + +static CPIListener * +_conjureIPObject(CPIInterfaceIPTunnelType type, const char *addressString, uint16_t port, const char *symbolic) +{ + struct sockaddr_in sin; + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + int result = inet_aton(addressString, &sin.sin_addr); + assertTrue(result == 1, "failed inet_aton: (%d) %s", errno, strerror(errno)); + + CPIAddress *address = cpiAddress_CreateFromInet(&sin); + CPIListener *listener = cpiListener_CreateIP(type, address, symbolic); + cpiAddress_Destroy(&address); + + return listener; +} + +LONGBOW_TEST_RUNNER(cpi_ConnectionEthernet) +{ + // 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); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(cpi_ConnectionEthernet) +{ + 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(cpi_ConnectionEthernet) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, cpiListener_CreateEther); + LONGBOW_RUN_TEST_CASE(Global, cpiListener_CreateIP); + LONGBOW_RUN_TEST_CASE(Global, cpiListener_Equals_Ether); + LONGBOW_RUN_TEST_CASE(Global, cpiListener_Equals_IP); + LONGBOW_RUN_TEST_CASE(Global, cpiListener_CreateAddMessage); + LONGBOW_RUN_TEST_CASE(Global, cpiListener_CreateRemoveMessage); + LONGBOW_RUN_TEST_CASE(Global, cpiListener_IsAddMessage); + LONGBOW_RUN_TEST_CASE(Global, cpiListener_IsRemoveMessage); + LONGBOW_RUN_TEST_CASE(Global, cpiListener_FromControl_Ether); + LONGBOW_RUN_TEST_CASE(Global, cpiListener_FromControl_IP); + LONGBOW_RUN_TEST_CASE(Global, cpiListener_IsEtherEncap); + LONGBOW_RUN_TEST_CASE(Global, cpiListener_IsIPEncap); + LONGBOW_RUN_TEST_CASE(Global, cpiListener_GetEtherType); + + LONGBOW_RUN_TEST_CASE(Global, cpiListener_GetInterfaceName); + LONGBOW_RUN_TEST_CASE(Global, cpiListener_GetSymbolicName); + LONGBOW_RUN_TEST_CASE(Global, cpiListener_GetAddress); + + LONGBOW_RUN_TEST_CASE(Global, cpiListener_IsProtocolUdp); + LONGBOW_RUN_TEST_CASE(Global, cpiListener_IsProtocolTcp); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + 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, cpiListener_CreateEther) +{ + CPIListener *listener = cpiListener_CreateEther("eth0", 0x0801, "puppy"); + assertNotNull(listener, "Got null IP based listener"); + cpiListener_Release(&listener); +} + +LONGBOW_TEST_CASE(Global, cpiListener_CreateIP) +{ + CPIListener *listener = _conjureIPObject(IPTUN_UDP, "127.0.0.1", 9596, "puppy"); + assertNotNull(listener, "Got null IP based listener"); + cpiListener_Release(&listener); +} + +LONGBOW_TEST_CASE(Global, cpiListener_Equals_Ether) +{ + CPIListener *x = cpiListener_CreateEther("eth0", 0x0801, "puppy"); + CPIListener *y = cpiListener_CreateEther("eth0", 0x0801, "puppy"); + CPIListener *z = cpiListener_CreateEther("eth0", 0x0801, "puppy"); + + CPIListener *t = cpiListener_CreateEther("eth1", 0x0801, "puppy"); + CPIListener *u = cpiListener_CreateEther("eth0", 0x0802, "puppy"); + CPIListener *v = cpiListener_CreateEther("eth0", 0x0801, "kitten"); + + assertEqualsContract(cpiListener_Equals, x, y, z, t, u, v); + + cpiListener_Release(&x); + cpiListener_Release(&y); + cpiListener_Release(&z); + cpiListener_Release(&t); + cpiListener_Release(&u); + cpiListener_Release(&v); +} + +LONGBOW_TEST_CASE(Global, cpiListener_Equals_IP) +{ + CPIListener *x = _conjureIPObject(IPTUN_UDP, "127.0.0.1", 9596, "puppy"); + CPIListener *y = _conjureIPObject(IPTUN_UDP, "127.0.0.1", 9596, "puppy"); + CPIListener *z = _conjureIPObject(IPTUN_UDP, "127.0.0.1", 9596, "puppy"); + + CPIListener *t = _conjureIPObject(IPTUN_TCP, "127.0.0.1", 9596, "puppy"); + CPIListener *u = _conjureIPObject(IPTUN_UDP, "127.0.2.1", 9596, "puppy"); + CPIListener *v = _conjureIPObject(IPTUN_UDP, "127.0.0.1", 1111, "puppy"); + CPIListener *w = _conjureIPObject(IPTUN_UDP, "127.0.0.1", 9596, "kitten"); + + assertEqualsContract(cpiListener_Equals, x, y, z, t, u, v, w); + + cpiListener_Release(&x); + cpiListener_Release(&y); + cpiListener_Release(&z); + cpiListener_Release(&t); + cpiListener_Release(&u); + cpiListener_Release(&v); + cpiListener_Release(&w); +} + +LONGBOW_TEST_CASE(Global, cpiListener_CreateAddMessage) +{ + const char *truthFormat = "{\"CPI_REQUEST\":{\"SEQUENCE\":%d,\"%s\":{\"IFNAME\":\"eth0\",\"ETHERTYPE\":2049,\"SYMBOLIC\":\"puppy\"}}}"; + + char buffer[1024]; + + // Create the add message + CPIListener *listener = cpiListener_CreateEther("eth0", 0x0801, "puppy"); + CCNxControl *control = cpiListener_CreateAddMessage(listener); + assertNotNull(control, "Got null control message"); + + // extract the sequence number to put in the truth string + PARCJSON *json = ccnxControl_GetJson(control); + uint64_t seqnum = controlPlaneInterface_GetSequenceNumber(json); + sprintf(buffer, truthFormat, (int) seqnum, KEY_ADDLISTENER); + + char *testString = parcJSON_ToCompactString(json); + assertTrue(strcmp(buffer, testString) == 0, "Got wrong JSON, expected\n%s\nGot\n%s\n", buffer, testString); + parcMemory_Deallocate((void **) &testString); + + ccnxControl_Release(&control); + cpiListener_Release(&listener); +} + +LONGBOW_TEST_CASE(Global, cpiListener_CreateRemoveMessage) +{ +#if defined(__APPLE__) + const char *truthFormat = "{\"CPI_REQUEST\":{\"SEQUENCE\":%d,\"%s\":{\"IPROTO\":\"UDP\",\"ADDR\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIlfH8AAAEAAAAAAAAAAA==\"},\"SYMBOLIC\":\"puppy\"}}}"; +#elif defined(__linux__) + const char *truthFormat = "{\"CPI_REQUEST\":{\"SEQUENCE\":%d,\"%s\":{\"IPROTO\":\"UDP\",\"ADDR\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAlfH8AAAEAAAAAAAAAAA==\"},\"SYMBOLIC\":\"puppy\"}}}"; +#else + // Case 1033 + testUnimplemented("Platform not supported"); + return; +#endif + + char buffer[1024]; + + // Create the remove message + CPIListener *listener = _conjureIPObject(IPTUN_UDP, "127.0.0.1", 9596, "puppy"); + CCNxControl *control = cpiListener_CreateRemoveMessage(listener); + assertNotNull(control, "Got null control message"); + + // extract the sequence number to put in the truth string + PARCJSON *json = ccnxControl_GetJson(control); + uint64_t seqnum = controlPlaneInterface_GetSequenceNumber(json); + sprintf(buffer, truthFormat, (int) seqnum, KEY_REMOVELISTENER); + + char *testString = parcJSON_ToCompactString(json); + assertTrue(strcmp(buffer, testString) == 0, "Got wrong JSON, expected\n%s\nGot\n%s\n", buffer, testString); + parcMemory_Deallocate((void **) &testString); + + ccnxControl_Release(&control); + cpiListener_Release(&listener); +} + +LONGBOW_TEST_CASE(Global, cpiListener_IsAddMessage) +{ + CPIListener *listener = cpiListener_CreateEther("eth0", 0x0801, "puppy"); + CCNxControl *control = cpiListener_CreateAddMessage(listener); + assertNotNull(control, "Got null control message"); + + bool test = cpiListener_IsAddMessage(control); + assertTrue(test, "Add message denies it is one."); + + ccnxControl_Release(&control); + cpiListener_Release(&listener); +} + +LONGBOW_TEST_CASE(Global, cpiListener_IsRemoveMessage) +{ + CPIListener *listener = cpiListener_CreateEther("eth0", 0x0801, "puppy"); + CCNxControl *control = cpiListener_CreateRemoveMessage(listener); + assertNotNull(control, "Got null control message"); + + bool test = cpiListener_IsRemoveMessage(control); + assertTrue(test, "Add message denies it is one."); + + ccnxControl_Release(&control); + cpiListener_Release(&listener); +} + +LONGBOW_TEST_CASE(Global, cpiListener_FromControl_Ether) +{ + CPIListener *listener = cpiListener_CreateEther("eth0", 0x0801, "puppy"); + CCNxControl *control = cpiListener_CreateAddMessage(listener); + + CPIListener *test = cpiListener_FromControl(control); + assertTrue(cpiListener_Equals(listener, test), "Listeners do not match") + { + printf("Expenected:\n"); + char *str = parcJSON_ToString(ccnxControl_GetJson(control)); + printf(" %s\n", str); + parcMemory_Deallocate((void **) &str); + + printf("Got:\n"); + CCNxControl *testControl = cpiListener_CreateAddMessage(test); + str = parcJSON_ToString(ccnxControl_GetJson(testControl)); + printf(" %s\n", str); + parcMemory_Deallocate((void **) &str); + ccnxControl_Release(&testControl); + } + + ccnxControl_Release(&control); + cpiListener_Release(&test); + cpiListener_Release(&listener); +} + + +LONGBOW_TEST_CASE(Global, cpiListener_FromControl_IP) +{ + CPIListener *listener = _conjureIPObject(IPTUN_UDP, "127.0.0.1", 9596, "puppy"); + CCNxControl *control = cpiListener_CreateAddMessage(listener); + + CPIListener *test = cpiListener_FromControl(control); + assertTrue(cpiListener_Equals(listener, test), "Listeners do not match") + { + printf("Expenected:\n"); + char *str = parcJSON_ToString(ccnxControl_GetJson(control)); + printf(" %s\n", str); + parcMemory_Deallocate((void **) &str); + + printf("Got:\n"); + CCNxControl *testControl = cpiListener_CreateAddMessage(test); + str = parcJSON_ToString(ccnxControl_GetJson(testControl)); + printf(" %s\n", str); + parcMemory_Deallocate((void **) &str); + ccnxControl_Release(&testControl); + } + + ccnxControl_Release(&control); + cpiListener_Release(&test); + cpiListener_Release(&listener); +} + +LONGBOW_TEST_CASE(Global, cpiListener_IsEtherEncap) +{ + CPIListener *x = cpiListener_CreateEther("eth0", 0x0801, "puppy"); + bool isTrue = cpiListener_IsEtherEncap(x); + assertTrue(isTrue, "Ether listener says it is not ether"); + cpiListener_Release(&x); +} + +LONGBOW_TEST_CASE(Global, cpiListener_IsIPEncap) +{ + CPIListener *x = _conjureIPObject(IPTUN_UDP, "127.0.0.1", 9596, "puppy"); + bool isTrue = cpiListener_IsIPEncap(x); + assertTrue(isTrue, "IP listener says it is not IP"); + cpiListener_Release(&x); +} + +LONGBOW_TEST_CASE(Global, cpiListener_GetAddress) +{ + CPIListener *x = _conjureIPObject(IPTUN_UDP, "127.0.0.1", 9596, "puppy"); + CPIAddress *test = cpiListener_GetAddress(x); + assertNotNull(test, "Got null address for IP listener"); + + struct sockaddr_in sin; + cpiAddress_GetInet(test, &sin); + assertTrue(htons(sin.sin_port) == 9596, "Wrong port expected %u got %u", 9695, htons(sin.sin_port)); + + uint32_t testip = htonl(sin.sin_addr.s_addr); + uint32_t truthip = 0x7F000001; + + assertTrue(testip == truthip, "Wrong IP address expected %#08x got %#08x", truthip, testip); + + cpiListener_Release(&x); +} + +LONGBOW_TEST_CASE(Global, cpiListener_GetEtherType) +{ + CPIListener *x = cpiListener_CreateEther("eth0", 0x0801, "puppy"); + uint16_t test = cpiListener_GetEtherType(x); + assertTrue(test == 0x0801, "Wrong ethertype, got %04x expected %04x", test, 0x0801); + cpiListener_Release(&x); +} + +LONGBOW_TEST_CASE(Global, cpiListener_GetInterfaceName) +{ + CPIListener *x = cpiListener_CreateEther("eth0", 0x0801, "puppy"); + const char *test = cpiListener_GetInterfaceName(x); + assertTrue(strcmp(test, "eth0") == 0, "Wrong interface name, got '%s' expected '%s'", test, "eth0"); + cpiListener_Release(&x); +} + +LONGBOW_TEST_CASE(Global, cpiListener_GetSymbolicName) +{ + CPIListener *x = cpiListener_CreateEther("eth0", 0x0801, "puppy"); + const char *test = cpiListener_GetSymbolicName(x); + assertTrue(strcmp(test, "puppy") == 0, "Wrong symbolic name, got '%s' expected '%s'", test, "puppy"); + cpiListener_Release(&x); +} + +LONGBOW_TEST_CASE(Global, cpiListener_IsProtocolUdp) +{ + CPIListener *x = _conjureIPObject(IPTUN_UDP, "127.0.0.1", 9596, "puppy"); + assertTrue(cpiListener_IsProtocolUdp(x), "UDP listener did not say it was UDP"); + cpiListener_Release(&x); +} + +LONGBOW_TEST_CASE(Global, cpiListener_IsProtocolTcp) +{ + CPIListener *x = _conjureIPObject(IPTUN_TCP, "127.0.0.1", 9596, "puppy"); + assertTrue(cpiListener_IsProtocolTcp(x), "TCP listener did not say it was TCP"); + cpiListener_Release(&x); +} + +// ========================================= + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_ConnectionEthernet); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_ManageLinks.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_ManageLinks.c new file mode 100644 index 00000000..381e49b1 --- /dev/null +++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_ManageLinks.c @@ -0,0 +1,266 @@ +/* + * 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 "../cpi_ManageLinks.c" +#include <LongBow/testing.h> + +#include <parc/algol/parc_SafeMemory.h> +#include <parc/algol/parc_Network.h> +#include <inttypes.h> + + + +static const short testCpiManageLinks_MetisPort = 9695; + +LONGBOW_TEST_RUNNER(cpi_ManageLinks) +{ + // 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); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(cpi_ManageLinks) +{ + 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(cpi_ManageLinks) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, cpiLinks_CreateIPTunnel); + LONGBOW_RUN_TEST_CASE(Global, cpiLinks_CreateInterfaceListRequest); + LONGBOW_RUN_TEST_CASE(Global, cpiLinks_InterfacesFromControlMessage); + LONGBOW_RUN_TEST_CASE(Global, cpiLinks_InterfaceIPTunnelFromControlMessage); + + LONGBOW_RUN_TEST_CASE(Global, cpiLinks_CreateConnectionListRequest); + LONGBOW_RUN_TEST_CASE(Global, cpiLinks_ConnectionListFromControlMessage); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + 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, cpiLinks_CreateIPTunnel) +{ + // The JSON representation depends on the system sockaddr_in format, which + // varies platform to platform. Note that the port number is encoded in the JSON, + // so if you change the port the test will fail. +#if defined(__APPLE__) + char *truth_format = "{\"CPI_REQUEST\":{\"SEQUENCE\":%" PRIu64 ",\"CREATE_TUNNEL\":{\"TUNNEL\":{\"IFIDX\":0,\"SYMBOLIC\":\"tun0\",\"TUNTYPE\":\"TCP\",\"SRC\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIAAAAAAAAAAAAAAAAAAA==\"},\"DST\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIl338AAAEAAAAAAAAAAA==\"}}}}}"; +#elif defined(__linux__) + char *truth_format = "{\"CPI_REQUEST\":{\"SEQUENCE\":%" PRIu64 ",\"CREATE_TUNNEL\":{\"TUNNEL\":{\"IFIDX\":0,\"SYMBOLIC\":\"tun0\",\"TUNTYPE\":\"TCP\",\"SRC\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAAAAAAAAAAAAAAAAAAAA==\"},\"DST\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAl338AAAEAAAAAAAAAAA==\"}}}}}"; +#else + // Case 1033 + testUnimplemented("Platform not supported"); + return; +#endif + + // --------------------------- + // Tunnel addresses + struct sockaddr_in sockaddr_any; + memset(&sockaddr_any, 0, sizeof(sockaddr_any)); + sockaddr_any.sin_family = PF_INET; + sockaddr_any.sin_addr.s_addr = INADDR_ANY; + + CPIAddress *source = cpiAddress_CreateFromInet(&sockaddr_any); + + struct sockaddr_in sockaddr_dst; + memset(&sockaddr_dst, 0, sizeof(sockaddr_dst)); + sockaddr_dst.sin_family = PF_INET; + sockaddr_dst.sin_port = htons(testCpiManageLinks_MetisPort); + inet_pton(AF_INET, "127.0.0.1", &(sockaddr_dst.sin_addr)); + + CPIAddress *destination = cpiAddress_CreateFromInet(&sockaddr_dst); + + // --------------------------- + + CPIInterfaceIPTunnel *iptun = cpiInterfaceIPTunnel_Create(0, source, destination, IPTUN_TCP, "tun0"); + CCNxControl *control = ccnxControl_CreateIPTunnelRequest(iptun); + + char buffer[1024]; + sprintf(buffer, truth_format, cpi_GetSequenceNumber(control)); + + PARCJSON *json = ccnxControl_GetJson(control); + char *test_string = parcJSON_ToCompactString(json); + assertTrue(strcmp(buffer, test_string) == 0, "JSON strings did not match.\nexpected %s\ngot %s\n", buffer, test_string); + parcMemory_Deallocate((void **) &test_string); + + ccnxControl_Release(&control); + cpiInterfaceIPTunnel_Release(&iptun); +} + +LONGBOW_TEST_CASE(Global, cpiLinks_CreateInterfaceListRequest) +{ + char template[] = "{\"CPI_REQUEST\":{\"SEQUENCE\":%llu,\"INTERFACE_LIST\":{}}}"; + char truth[1024]; + + CCNxControl *control = ccnxControl_CreateInterfaceListRequest(); + + uint64_t seqnum = cpi_GetSequenceNumber(control); + + sprintf(truth, template, seqnum); + + PARCJSON *json = ccnxControl_GetJson(control); + char *str = parcJSON_ToCompactString(json); + assertTrue(strcmp(truth, str) == 0, "Did not get right json, expected '%s' got '%s'", truth, str); + parcMemory_Deallocate((void **) &str); + + ccnxControl_Release(&control); +} + +LONGBOW_TEST_CASE(Global, cpiLinks_InterfacesFromControlMessage) +{ + CCNxControl *control = ccnxControl_CreateInterfaceListRequest(); + + CPIInterfaceSet *truth = cpiInterfaceSet_Create(); + CPIInterface *iface = cpiInterface_Create("eth0", 11, false, true, 1500); + cpiInterfaceSet_Add(truth, iface); + + PARCJSON *json = cpiInterfaceSet_ToJson(truth); + CCNxControl *response = cpi_CreateResponse(control, json); + parcJSON_Release(&json); + CPIInterfaceSet *test = cpiLinks_InterfacesFromControlMessage(response); + + assertTrue(cpiInterfaceSet_Equals(test, truth), "Interface sets not equal"); + + ccnxControl_Release(&response); + cpiInterfaceSet_Destroy(&truth); + cpiInterfaceSet_Destroy(&test); + ccnxControl_Release(&control); +} + +LONGBOW_TEST_CASE(Global, cpiLinks_InterfaceIPTunnelFromControlMessage) +{ + // --------------------------- + // Tunnel addresses + struct sockaddr_in sockaddr_any; + memset(&sockaddr_any, 0, sizeof(sockaddr_any)); + sockaddr_any.sin_family = PF_INET; + sockaddr_any.sin_addr.s_addr = INADDR_ANY; + + CPIAddress *source = cpiAddress_CreateFromInet(&sockaddr_any); + + struct sockaddr_in sockaddr_dst; + memset(&sockaddr_dst, 0, sizeof(sockaddr_dst)); + sockaddr_dst.sin_family = PF_INET; + sockaddr_dst.sin_port = htons(testCpiManageLinks_MetisPort); + inet_pton(AF_INET, "127.0.0.1", &(sockaddr_dst.sin_addr)); + + CPIAddress *destination = cpiAddress_CreateFromInet(&sockaddr_dst); + + // --------------------------- + + CPIInterfaceIPTunnel *truth = cpiInterfaceIPTunnel_Create(0, source, destination, IPTUN_TCP, "tun0"); + CCNxControl *control = ccnxControl_CreateIPTunnelRequest(truth); + + CPIInterfaceIPTunnel *test = cpiLinks_CreateIPTunnelFromControlMessage(control); + + assertTrue(cpiInterfaceIPTunnel_Equals(truth, test), "InterfaceIPTunnels do not match"); + + ccnxControl_Release(&control); + cpiInterfaceIPTunnel_Release(&test); + cpiInterfaceIPTunnel_Release(&truth); +} + +LONGBOW_TEST_CASE(Global, cpiLinks_CreateConnectionListRequest) +{ + char template[] = "{\"CPI_REQUEST\":{\"SEQUENCE\":%llu,\"CONNECTION_LIST\":{}}}"; + char truth[1024]; + + CCNxControl *control = ccnxControl_CreateConnectionListRequest(); + uint64_t seqnum = cpi_GetSequenceNumber(control); + + sprintf(truth, template, seqnum); + + PARCJSON *json = ccnxControl_GetJson(control); + char *str = parcJSON_ToCompactString(json); + + assertTrue(strcmp(truth, str) == 0, "Did not get right json, expected '%s' got '%s'", truth, str); + parcMemory_Deallocate((void **) &str); + + ccnxControl_Release(&control); +} + +LONGBOW_TEST_CASE(Global, cpiLinks_ConnectionListFromControlMessage) +{ + // The request we'll create a response to + CCNxControl *request = ccnxControl_CreateConnectionListRequest(); + + // --------------------------- + // Tunnel addresses + struct sockaddr_in sockaddr_any; + memset(&sockaddr_any, 0, sizeof(sockaddr_any)); + sockaddr_any.sin_family = PF_INET; + sockaddr_any.sin_addr.s_addr = INADDR_ANY; + + CPIAddress *source = cpiAddress_CreateFromInet(&sockaddr_any); + + struct sockaddr_in sockaddr_dst; + memset(&sockaddr_dst, 0, sizeof(sockaddr_dst)); + sockaddr_dst.sin_family = PF_INET; + sockaddr_dst.sin_port = htons(testCpiManageLinks_MetisPort); + inet_pton(AF_INET, "127.0.0.1", &(sockaddr_dst.sin_addr)); + + CPIAddress *destination = cpiAddress_CreateFromInet(&sockaddr_dst); + + // --------------------------- + + CPIConnectionList *truth_list = cpiConnectionList_Create(); + cpiConnectionList_Append(truth_list, cpiConnection_Create(0, source, destination, cpiConnection_TCP)); + + PARCJSON *json = cpiConnectionList_ToJson(truth_list); + CCNxControl *response = cpi_CreateResponse(request, json); + parcJSON_Release(&json); + CPIConnectionList *test = cpiLinks_ConnectionListFromControlMessage(response); + + assertTrue(cpiConnectionList_Equals(truth_list, test), "InterfaceIPTunnels do not match"); + + ccnxControl_Release(&response); + ccnxControl_Release(&request); + cpiConnectionList_Destroy(&test); + cpiConnectionList_Destroy(&truth_list); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_ManageLinks); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_NameRouteType.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_NameRouteType.c new file mode 100644 index 00000000..85175a7e --- /dev/null +++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_NameRouteType.c @@ -0,0 +1,93 @@ +/* + * 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 "../cpi_NameRouteType.c" +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> + +LONGBOW_TEST_RUNNER(cpi_NameRouteType) +{ + // 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); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(cpi_NameRouteType) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(cpi_NameRouteType) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, cpiNameRouteType_ToString); + LONGBOW_RUN_TEST_CASE(Global, cpiNameRouteType_FromString); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + 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, cpiNameRouteType_ToString) +{ + int numEntries = sizeof(nameRouteTypeString) / sizeof(nameRouteTypeString[0]); + + for (int i = 0; i < numEntries; i++) { + if (nameRouteTypeString[i].type != 0) { + assertTrue(cpiNameRouteType_ToString(nameRouteTypeString[i].type) != NULL, "Expected non-NULL type name"); + } + } +} + +LONGBOW_TEST_CASE(Global, cpiNameRouteType_FromString) +{ + int numEntries = sizeof(nameRouteTypeString) / sizeof(nameRouteTypeString[0]); + + for (int i = 0; i < numEntries; i++) { + if (nameRouteTypeString[i].str != NULL) { + CPINameRouteType type = cpiNameRouteType_FromString(nameRouteTypeString[i].str); + assertTrue(type == cpiNameRouteType_DEFAULT || type == cpiNameRouteType_EXACT_MATCH || type == cpiNameRouteType_LONGEST_MATCH, "unexpected route type"); + } + } + // Test a name that doesn't exist. (need to catch the trap) Case 1034 +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_NameRouteType); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Registration.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Registration.c new file mode 100644 index 00000000..6f15c0e0 --- /dev/null +++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_Registration.c @@ -0,0 +1,72 @@ +/* + * 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 <LongBow/unit-test.h> + +#include <parc/algol/parc_SafeMemory.h> + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../cpi_NameRouteProtocolType.c" + + +LONGBOW_TEST_RUNNER(cpi_NameRouteProtocolType) +{ + // 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); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(cpi_NameRouteProtocolType) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(cpi_NameRouteProtocolType) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + 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; +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_NameRouteProtocolType); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_RouteEntry.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_RouteEntry.c new file mode 100644 index 00000000..97b85ead --- /dev/null +++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_RouteEntry.c @@ -0,0 +1,547 @@ +/* + * 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 <config.h> + +#include <stdio.h> + +#include <LongBow/unit-test.h> +#include <parc/algol/parc_Memory.h> +#include <parc/algol/parc_SafeMemory.h> +#include <LongBow/unit-test.h> + +#define __STDC_FORMAT_MACROS +#include <inttypes.h> + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. +#include "../cpi_RouteEntry.c" + +LONGBOW_TEST_RUNNER(cpi_RouteEntry) +{ + // 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(Getters); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(cpi_RouteEntry) +{ + 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(cpi_RouteEntry) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_Copy); + LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_Equals); + LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_Create_Destroy); + LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_CreateSymbolic); + + LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_ToJson_1); + LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_ToJson_2); + LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_ToJson_3); + LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_ToJson_4); + + LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_FromJson_1); + LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_FromJson_2); + LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_FromJson_3); + LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_FromJson_4); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + 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, cpiRouteEntry_Create_Destroy) +{ + CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger"); + unsigned ifidx = 55; + unsigned cost = 4; + + CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, NULL, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, cost); + cpiRouteEntry_Destroy(&route); + + assertTrue(parcMemory_Outstanding() == 0, "Memory imbalance on create/destroy: %u", parcMemory_Outstanding()); +} + +LONGBOW_TEST_CASE(Global, cpiRouteEntry_Copy) +{ + CCNxName *prefix_a = ccnxName_CreateFromCString("lci:/howdie/stranger"); + unsigned ifidx = 55; + CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 }); + struct timeval lifetime = { 3600, 0 }; + unsigned cost = 200; + + CPIRouteEntry *a = cpiRouteEntry_Create(prefix_a, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost); + CPIRouteEntry *b = cpiRouteEntry_Copy(a); + + assertTrue(cpiRouteEntry_Equals(a, b), "Copy did not compare as equals"); + cpiAddress_Destroy(&nexthop); + cpiRouteEntry_Destroy(&a); + cpiRouteEntry_Destroy(&b); +} + +LONGBOW_TEST_CASE(Global, cpiRouteEntry_Equals) +{ + CCNxName *prefix_a = ccnxName_CreateFromCString("lci:/howdie/stranger"); + CCNxName *prefix_b = ccnxName_Copy(prefix_a); + unsigned ifidx = 55; + CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 }); + struct timeval lifetime = { 3600, 0 }; + unsigned cost = 200; + + CPIRouteEntry *a = cpiRouteEntry_Create(prefix_a, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost); + CPIRouteEntry *b = cpiRouteEntry_Create(prefix_b, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost); + + assertTrue(cpiRouteEntry_Equals(a, b), "Equals did not compare correctly"); + + cpiRouteEntry_Destroy(&a); + cpiRouteEntry_Destroy(&b); + cpiAddress_Destroy(&nexthop); +} + +LONGBOW_TEST_CASE(Global, cpiRouteEntry_CreateSymbolic) +{ + CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger"); + unsigned cost = 4; + + CPIRouteEntry *route = cpiRouteEntry_CreateSymbolic(prefix, "tun0", cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, cost); + cpiRouteEntry_Destroy(&route); + + assertTrue(parcMemory_Outstanding() == 0, "Memory imbalance on create/destroy: %u", parcMemory_Outstanding()); +} + + +/** + * Add route with all options + */ +LONGBOW_TEST_CASE(Global, cpiRouteEntry_ToJson_1) +{ + // The JSON representation depends on the system sockaddr_in format, which + // varies platform to platform. +#if defined(__APPLE__) + char truth[] = "{\"PREFIX\":\"ccnx:/howdie/stranger\",\"INTERFACE\":55,\"FLAGS\":0,\"NEXTHOP\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIAAAQDAgEAAAAAAAAAAA==\"},\"PROTOCOL\":\"STATIC\",\"ROUTETYPE\":\"LONGEST\",\"COST\":200,\"LIFETIME\":[3600,0]}"; +#elif defined(__linux__) + char truth[] = "{\"PREFIX\":\"ccnx:/howdie/stranger\",\"INTERFACE\":55,\"FLAGS\":0,\"NEXTHOP\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAAAAQDAgEAAAAAAAAAAA==\"},\"PROTOCOL\":\"STATIC\",\"ROUTETYPE\":\"LONGEST\",\"COST\":200,\"LIFETIME\":[3600,0]}"; +#else + // Case 1033 + testUnimplemented("Platform not supported"); + return; +#endif + + CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger"); + unsigned ifidx = 55; + CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 }); + struct timeval lifetime = { 3600, 0 }; + unsigned cost = 200; + + CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost); + + PARCJSON *test_json = cpiRouteEntry_ToJson(route); + char *test = parcJSON_ToCompactString(test_json); + assertTrue(strcasecmp(truth, test) == 0, "Route json does not match, expected '%s', got '%s'", truth, test); + parcMemory_Deallocate((void **) &test); + + cpiRouteEntry_Destroy(&route); + cpiAddress_Destroy(&nexthop); + parcJSON_Release(&test_json); +} + +/** + * Add route without lifeitme + */ +LONGBOW_TEST_CASE(Global, cpiRouteEntry_ToJson_2) +{ + // The JSON representation depends on the system sockaddr_in format, which + // varies platform to platform. +#if defined(__APPLE__) + char truth[] = "{\"PREFIX\":\"ccnx:/howdie/stranger\",\"INTERFACE\":55,\"FLAGS\":0,\"NEXTHOP\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AAIAAAQDAgEAAAAAAAAAAA==\"},\"PROTOCOL\":\"STATIC\",\"ROUTETYPE\":\"LONGEST\",\"COST\":200}"; +#elif defined(__linux__) + char truth[] = "{\"PREFIX\":\"ccnx:/howdie/stranger\",\"INTERFACE\":55,\"FLAGS\":0,\"NEXTHOP\":{\"ADDRESSTYPE\":\"INET\",\"DATA\":\"AgAAAAQDAgEAAAAAAAAAAA==\"},\"PROTOCOL\":\"STATIC\",\"ROUTETYPE\":\"LONGEST\",\"COST\":200}"; +#else + // Case 1033 + testUnimplemented("Platform not supported"); + return; +#endif + + CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger"); + unsigned ifidx = 55; + CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 }); + unsigned cost = 200; + + CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, cost); + PARCJSON *test_json = cpiRouteEntry_ToJson(route); + char *test = parcJSON_ToCompactString(test_json); + assertTrue(strcasecmp(truth, test) == 0, "Route json does not match, expected '%s', got '%s'", truth, test); + parcMemory_Deallocate((void **) &test); + + cpiRouteEntry_Destroy(&route); + cpiAddress_Destroy(&nexthop); + parcJSON_Release(&test_json); +} + +/** + * Add route without lifeitme or nexthop + */ +LONGBOW_TEST_CASE(Global, cpiRouteEntry_ToJson_3) +{ + char truth[] = "{\"PREFIX\":\"ccnx:/howdie/stranger\",\"INTERFACE\":55,\"FLAGS\":0,\"PROTOCOL\":\"STATIC\",\"ROUTETYPE\":\"LONGEST\",\"COST\":200}"; + + CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger"); + unsigned ifidx = 55; + unsigned cost = 200; + + CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, NULL, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, cost); + + PARCJSON *test_json = cpiRouteEntry_ToJson(route); + char *test = parcJSON_ToCompactString(test_json); + assertTrue(strcasecmp(truth, test) == 0, "Control message json does not match, expected '%s', got '%s'", truth, test); + parcMemory_Deallocate((void **) &test); + + cpiRouteEntry_Destroy(&route); + parcJSON_Release(&test_json); +} + +/** + * Add route with symbolic name + */ +LONGBOW_TEST_CASE(Global, cpiRouteEntry_ToJson_4) +{ + // The JSON representation depends on the system sockaddr_in format, which + // varies platform to platform. + char truth[] = "{\"PREFIX\":\"ccnx:/howdie/stranger\",\"SYMBOLIC\":\"tun0\",\"INTERFACE\":55,\"FLAGS\":0,\"PROTOCOL\":\"STATIC\",\"ROUTETYPE\":\"LONGEST\",\"COST\":200,\"LIFETIME\":[3600,0]}"; + + CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger"); + unsigned ifidx = 55; + struct timeval lifetime = { 3600, 0 }; + unsigned cost = 200; + + CPIRouteEntry *route = cpiRouteEntry_CreateSymbolic(prefix, "tun0", cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost); + cpiRouteEntry_SetInterfaceIndex(route, ifidx); + + PARCJSON *test_json = cpiRouteEntry_ToJson(route); + char *test = parcJSON_ToCompactString(test_json); + assertTrue(strcasecmp(truth, test) == 0, "Route json does not match, expected '%s', got '%s'", truth, test); + parcMemory_Deallocate((void **) &test); + + cpiRouteEntry_Destroy(&route); + parcJSON_Release(&test_json); +} + +/** + * Add route with all options + */ +LONGBOW_TEST_CASE(Global, cpiRouteEntry_FromJson_1) +{ + CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger"); + unsigned ifidx = 55; + CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 }); + struct timeval lifetime = { 3600, 0 }; + unsigned cost = 200; + + CPIRouteEntry *route_truth = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost); + + PARCJSON *truth_json = cpiRouteEntry_ToJson(route_truth); + + CPIRouteEntry *route_test = cpiRouteEntry_FromJson(truth_json); + assertTrue(cpiRouteEntry_Equals(route_truth, route_test), "FromJson does not match"); + + + cpiRouteEntry_Destroy(&route_truth); + cpiRouteEntry_Destroy(&route_test); + cpiAddress_Destroy(&nexthop); + parcJSON_Release(&truth_json); +} + +/** + * Add route without lifeitme + */ +LONGBOW_TEST_CASE(Global, cpiRouteEntry_FromJson_2) +{ + CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger"); + unsigned ifidx = 55; + CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 }); + unsigned cost = 200; + + CPIRouteEntry *route_truth = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, cost); + + PARCJSON *truth_json = cpiRouteEntry_ToJson(route_truth); + + CPIRouteEntry *route_test = cpiRouteEntry_FromJson(truth_json); + assertTrue(cpiRouteEntry_Equals(route_truth, route_test), "FromJson does not match"); + + + cpiRouteEntry_Destroy(&route_truth); + cpiRouteEntry_Destroy(&route_test); + cpiAddress_Destroy(&nexthop); + parcJSON_Release(&truth_json); +} + +/** + * Add route without lifeitme or nexthop + */ +LONGBOW_TEST_CASE(Global, cpiRouteEntry_FromJson_3) +{ + CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger"); + unsigned ifidx = 55; + unsigned cost = 200; + + CPIRouteEntry *route_truth = cpiRouteEntry_Create(prefix, ifidx, NULL, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, cost); + + PARCJSON *truth_json = cpiRouteEntry_ToJson(route_truth); + + CPIRouteEntry *route_test = cpiRouteEntry_FromJson(truth_json); + assertTrue(cpiRouteEntry_Equals(route_truth, route_test), "FromJson does not match"); + + + cpiRouteEntry_Destroy(&route_truth); + cpiRouteEntry_Destroy(&route_test); + parcJSON_Release(&truth_json); +} + +LONGBOW_TEST_CASE(Global, cpiRouteEntry_FromJson_4) +{ + CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger"); + unsigned ifidx = 55; + struct timeval lifetime = { 3600, 0 }; + unsigned cost = 200; + + CPIRouteEntry *route_truth = cpiRouteEntry_CreateSymbolic(prefix, "tun0", cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost); + cpiRouteEntry_SetInterfaceIndex(route_truth, ifidx); + + PARCJSON *truth_json = cpiRouteEntry_ToJson(route_truth); + + CPIRouteEntry *route_test = cpiRouteEntry_FromJson(truth_json); + assertTrue(cpiRouteEntry_Equals(route_truth, route_test), "FromJson does not match"); + + const char *symbolic = cpiRouteEntry_GetSymbolicName(route_test); + assertTrue(strcmp(symbolic, "tun0") == 0, "wrong symbolic name expected 'tun0' got '%s'", symbolic); + + cpiRouteEntry_Destroy(&route_truth); + cpiRouteEntry_Destroy(&route_test); + parcJSON_Release(&truth_json); +} + + +// ==================================================== + +LONGBOW_TEST_FIXTURE(Getters) +{ + LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_GetCost); + LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_GetInterfaceIndex); + LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_GetLifetime); + LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_GetNexthop); + LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_GetPrefix); + LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_GetRouteProtocolType); + LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_GetRouteType); + LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntry_GetSymbolicName); +} + +LONGBOW_TEST_FIXTURE_SETUP(Getters) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Getters) +{ + 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, cpiRouteEntry_GetCost) +{ + CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger"); + unsigned ifidx = 55; + CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 }); + struct timeval lifetime = { 3600, 0 }; + unsigned cost = 200; + + CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost); + + assertTrue(cpiRouteEntry_GetCost(route) == cost, "Got wrong cost, expected %u got %u", cost, cpiRouteEntry_GetCost(route)); + cpiAddress_Destroy(&nexthop); + cpiRouteEntry_Destroy(&route); +} + +LONGBOW_TEST_CASE(Global, cpiRouteEntry_GetInterfaceIndex) +{ + CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger"); + unsigned ifidx = 55; + CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 }); + struct timeval lifetime = { 3600, 0 }; + unsigned cost = 200; + + CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost); + + assertTrue(cpiRouteEntry_GetInterfaceIndex(route) == ifidx, "Got wrong cost, expected %u got %u", ifidx, cpiRouteEntry_GetInterfaceIndex(route)); + cpiAddress_Destroy(&nexthop); + cpiRouteEntry_Destroy(&route); +} + +LONGBOW_TEST_CASE(Global, cpiRouteEntry_GetLifetime) +{ + CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger"); + unsigned ifidx = 55; + CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 }); + struct timeval lifetime = { 3600, 0 }; + unsigned cost = 200; + + CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost); + + struct timeval test_time = cpiRouteEntry_GetLifetime(route); + + assertTrue(lifetime.tv_sec == test_time.tv_sec && lifetime.tv_usec == test_time.tv_usec, + "Got wrong lifetime, expected %.6f got %.6f", + lifetime.tv_sec + 1E-6 * lifetime.tv_usec, + test_time.tv_sec + 1E-6 * test_time.tv_usec); + cpiAddress_Destroy(&nexthop); + cpiRouteEntry_Destroy(&route); +} + +LONGBOW_TEST_CASE(Global, cpiRouteEntry_GetNexthop) +{ + CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger"); + unsigned ifidx = 55; + CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 }); + struct timeval lifetime = { 3600, 0 }; + unsigned cost = 200; + + CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost); + + const CPIAddress *test = cpiRouteEntry_GetNexthop(route); + + assertTrue(cpiAddress_Equals(nexthop, test), + "Got wrong nexthop, expected %s got %s", + cpiAddress_ToString(nexthop), + cpiAddress_ToString(test)); + + cpiAddress_Destroy(&nexthop); + cpiRouteEntry_Destroy(&route); +} + +LONGBOW_TEST_CASE(Global, cpiRouteEntry_GetPrefix) +{ + CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger"); + unsigned ifidx = 55; + CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 }); + struct timeval lifetime = { 3600, 0 }; + unsigned cost = 200; + + CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost); + + const CCNxName *test_prefix = cpiRouteEntry_GetPrefix(route); + + assertTrue(ccnxName_Equals(prefix, test_prefix), + "Got wrong name, expected %s got %s", + ccnxName_ToString(prefix), + ccnxName_ToString(test_prefix)); + + cpiAddress_Destroy(&nexthop); + cpiRouteEntry_Destroy(&route); +} + +LONGBOW_TEST_CASE(Global, cpiRouteEntry_GetRouteProtocolType) +{ + CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger"); + unsigned ifidx = 55; + CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 }); + struct timeval lifetime = { 3600, 0 }; + unsigned cost = 200; + + CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost); + + assertTrue(cpiRouteEntry_GetRouteProtocolType(route) == cpiNameRouteProtocolType_STATIC, + "Got wrong protocol, expected %d got %d", + cpiNameRouteProtocolType_STATIC, + cpiRouteEntry_GetRouteProtocolType(route)); + + cpiAddress_Destroy(&nexthop); + cpiRouteEntry_Destroy(&route); +} + +LONGBOW_TEST_CASE(Global, cpiRouteEntry_GetRouteType) +{ + CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger"); + unsigned ifidx = 55; + CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 }); + struct timeval lifetime = { 3600, 0 }; + unsigned cost = 200; + + CPIRouteEntry *route = cpiRouteEntry_Create(prefix, ifidx, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost); + + assertTrue(cpiRouteEntry_GetRouteType(route) == cpiNameRouteType_LONGEST_MATCH, + "Got wrong route type, expected %d got %d", + cpiNameRouteType_LONGEST_MATCH, + cpiRouteEntry_GetRouteType(route)); + + cpiAddress_Destroy(&nexthop); + cpiRouteEntry_Destroy(&route); +} + +LONGBOW_TEST_CASE(Global, cpiRouteEntry_GetSymbolicName) +{ + CCNxName *prefix = ccnxName_CreateFromCString("lci:/howdie/stranger"); + CPIAddress *nexthop = cpiAddress_CreateFromInet(&(struct sockaddr_in) { .sin_addr.s_addr = 0x01020304 }); + struct timeval lifetime = { 3600, 0 }; + unsigned cost = 200; + const char *symbolicName = "tun0"; + + CPIRouteEntry *route = cpiRouteEntry_CreateSymbolic(prefix, symbolicName, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, &lifetime, cost); + + const char *test = cpiRouteEntry_GetSymbolicName(route); + + assertTrue(strcmp(symbolicName, test) == 0, "Got wrong symbolic name, expected %s got %s", symbolicName, test); + cpiAddress_Destroy(&nexthop); + cpiRouteEntry_Destroy(&route); +} + +// ============================================================= + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_RouteEntry); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/libccnx-transport-rta/ccnx/api/control/test/test_cpi_RouteEntryList.c b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_RouteEntryList.c new file mode 100644 index 00000000..94f2b473 --- /dev/null +++ b/libccnx-transport-rta/ccnx/api/control/test/test_cpi_RouteEntryList.c @@ -0,0 +1,177 @@ +/* + * 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 "../cpi_RouteEntryList.c" +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> + +LONGBOW_TEST_RUNNER(cpi_RouteEntryList) +{ + // 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); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(cpi_RouteEntryList) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(cpi_RouteEntryList) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntryList_Append); + LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntryList_Create_Destroy); + LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntryList_FromJson); + LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntryList_FromJson_EmptyList); + LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntryList_Equals); + LONGBOW_RUN_TEST_CASE(Global, cpiRouteEntryList_ToJson); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) { + printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding()); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, cpiRouteEntryList_Append) +{ + CPIRouteEntryList *list = cpiRouteEntryList_Create(); + + CPIRouteEntry *entry = cpiRouteEntry_Create(ccnxName_CreateFromCString("ccnx:/hello"), 1, NULL, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, 1); + cpiRouteEntryList_Append(list, entry); + + assertTrue(parcArrayList_Size(list->listOfRouteEntries) == 1, "got wrong size, expected %u got %zu", 1, parcArrayList_Size(list->listOfRouteEntries)); + + cpiRouteEntryList_Destroy(&list); +} + +LONGBOW_TEST_CASE(Global, cpiRouteEntryList_Create_Destroy) +{ + CPIRouteEntryList *list = cpiRouteEntryList_Create(); + cpiRouteEntryList_Destroy(&list); + assertTrue(parcMemory_Outstanding() == 0, "Memory imbalance after create/destroy"); +} + +LONGBOW_TEST_CASE(Global, cpiRouteEntryList_FromJson) +{ + char truth_string[] = "{\"Routes\":[{\"PREFIX\":\"ccnx:/hello\",\"INTERFACE\":1,\"FLAGS\":0,\"PROTOCOL\":\"STATIC\",\"ROUTETYPE\":\"LONGEST\",\"COST\":1}]}"; + + CPIRouteEntryList *truth_list = cpiRouteEntryList_Create(); + CPIRouteEntry *entry = cpiRouteEntry_Create(ccnxName_CreateFromCString("ccnx:/hello"), 1, NULL, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, 1); + cpiRouteEntryList_Append(truth_list, entry); + + PARCJSON *truth_json = parcJSON_ParseString(truth_string); + CPIRouteEntryList *test_list = cpiRouteEntryList_FromJson(truth_json); + + assertTrue(cpiRouteEntryList_Equals(truth_list, test_list), "Lists do not match"); + + cpiRouteEntryList_Destroy(&test_list); + parcJSON_Release(&truth_json); + cpiRouteEntryList_Destroy(&truth_list); +} + +LONGBOW_TEST_CASE(Global, cpiRouteEntryList_FromJson_EmptyList) +{ + char truth_string[] = "{\"Routes\":[]}"; + + CPIRouteEntryList *truth_list = cpiRouteEntryList_Create(); + + PARCJSON *truth_json = parcJSON_ParseString(truth_string); + CPIRouteEntryList *test_list = cpiRouteEntryList_FromJson(truth_json); + + assertTrue(cpiRouteEntryList_Equals(truth_list, test_list), "Lists do not match"); + + cpiRouteEntryList_Destroy(&test_list); + parcJSON_Release(&truth_json); + cpiRouteEntryList_Destroy(&truth_list); +} + + +LONGBOW_TEST_CASE(Global, cpiRouteEntryList_Equals) +{ + CPIRouteEntryList *list_a = cpiRouteEntryList_Create(); + CPIRouteEntry *entry_a = cpiRouteEntry_Create(ccnxName_CreateFromCString("ccnx:/hello"), 1, NULL, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, 1); + cpiRouteEntryList_Append(list_a, entry_a); + + CPIRouteEntryList *list_b = cpiRouteEntryList_Create(); + CPIRouteEntry *entry_b = cpiRouteEntry_Create(ccnxName_CreateFromCString("ccnx:/hello"), 1, NULL, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, 1); + cpiRouteEntryList_Append(list_b, entry_b); + + CPIRouteEntryList *list_c = cpiRouteEntryList_Create(); + CPIRouteEntry *entry_c = cpiRouteEntry_Create(ccnxName_CreateFromCString("ccnx:/hello"), 1, NULL, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, 1); + cpiRouteEntryList_Append(list_c, entry_c); + + CPIRouteEntryList *unequal_length = cpiRouteEntryList_Create(); + CPIRouteEntry *entry_d = cpiRouteEntry_Create(ccnxName_CreateFromCString("ccnx:/hello"), 1, NULL, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, 1); + CPIRouteEntry *entry_e = cpiRouteEntry_Create(ccnxName_CreateFromCString("ccnx:/hello"), 1, NULL, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, 1); + cpiRouteEntryList_Append(unequal_length, entry_d); + cpiRouteEntryList_Append(unequal_length, entry_e); + + CPIRouteEntryList *unequal_value = cpiRouteEntryList_Create(); + CPIRouteEntry *entry_f = cpiRouteEntry_Create(ccnxName_CreateFromCString("ccnx:/hello"), 2, NULL, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, 1); + cpiRouteEntryList_Append(unequal_value, entry_f); + + assertEqualsContract(cpiRouteEntryList_Equals, list_a, list_b, list_c, unequal_length, unequal_value); + + cpiRouteEntryList_Destroy(&unequal_value); + cpiRouteEntryList_Destroy(&unequal_length); + + cpiRouteEntryList_Destroy(&list_a); + cpiRouteEntryList_Destroy(&list_b); + cpiRouteEntryList_Destroy(&list_c); +} + +LONGBOW_TEST_CASE(Global, cpiRouteEntryList_ToJson) +{ + char truth_string[] = "{\"Routes\":[{\"PREFIX\":\"ccnx:/hello\",\"INTERFACE\":1,\"FLAGS\":0,\"PROTOCOL\":\"STATIC\",\"ROUTETYPE\":\"LONGEST\",\"COST\":1}]}"; + + CPIRouteEntryList *list = cpiRouteEntryList_Create(); + + CPIRouteEntry *entry = cpiRouteEntry_Create(ccnxName_CreateFromCString("lci:/hello"), 1, NULL, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, 1); + cpiRouteEntryList_Append(list, entry); + + PARCJSON *json = cpiRouteEntryList_ToJson(list); + char *test = parcJSON_ToCompactString(json); + assertTrue(strcmp(truth_string, test) == 0, "Got wrong JSON.\nexpected: %s\ngot %s\n", truth_string, test); + parcMemory_Deallocate((void **) &test); + + parcJSON_Release(&json); + cpiRouteEntryList_Destroy(&list); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(cpi_RouteEntryList); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} |