diff options
Diffstat (limited to 'metis/ccnx/forwarder/metis/core/test')
13 files changed, 4361 insertions, 0 deletions
diff --git a/metis/ccnx/forwarder/metis/core/test/CMakeLists.txt b/metis/ccnx/forwarder/metis/core/test/CMakeLists.txt new file mode 100644 index 00000000..a1209868 --- /dev/null +++ b/metis/ccnx/forwarder/metis/core/test/CMakeLists.txt @@ -0,0 +1,22 @@ +# Enable gcov output for the tests +add_definitions(--coverage) +set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage") + +set(TestsExpectedToPass + test_metis_Connection + test_metis_ConnectionTable + test_metis_Dispatcher + test_metis_Forwarder + test_metis_Logger + test_metis_Message + test_metis_NumberSet + test_metis_StreamBuffer + test_metis_ConnectionList + test_metis_ThreadedForwarder +) + + +foreach(test ${TestsExpectedToPass}) + AddTest(${test}) +endforeach() + diff --git a/metis/ccnx/forwarder/metis/core/test/test_metis_Connection.c b/metis/ccnx/forwarder/metis/core/test/test_metis_Connection.c new file mode 100644 index 00000000..1fe904d1 --- /dev/null +++ b/metis/ccnx/forwarder/metis/core/test/test_metis_Connection.c @@ -0,0 +1,227 @@ +/* + * 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 "../metis_Connection.c" +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> +#include <parc/logging/parc_LogReporterTextStdout.h> + +#include <ccnx/forwarder/metis/testdata/metis_TestDataV1.h> + +#include "testrig_MetisIoOperations.h" + +LONGBOW_TEST_RUNNER(metis_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); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(metis_Connection) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(metis_Connection) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, metisConnection_Acquire); + LONGBOW_RUN_TEST_CASE(Global, metisConnection_Create_Destroy); + LONGBOW_RUN_TEST_CASE(Global, metisConnection_Send); + + LONGBOW_RUN_TEST_CASE(Global, metisConnection_GetConnectionId); + LONGBOW_RUN_TEST_CASE(Global, metisConnection_GetAddressPair); + LONGBOW_RUN_TEST_CASE(Global, metisConnection_IsUp); + LONGBOW_RUN_TEST_CASE(Global, metisConnection_IsLocal); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + MetisIoOperations *ops = mockIoOperationsData_CreateSimple(1, 2, 3, true, true, true); + longBowTestCase_SetClipBoardData(testCase, ops); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + MetisIoOperations *ops = longBowTestCase_GetClipBoardData(testCase); + mockIoOperationsData_Destroy(&ops); + + 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, metisConnection_Acquire) +{ + MetisIoOperations *ops = longBowTestCase_GetClipBoardData(testCase); + MetisConnection *conn = metisConnection_Create(ops); + + assertTrue(conn->refCount == 1, "Wrong refcount, got %u expected %u", conn->refCount, 1); + + MetisConnection *copy = metisConnection_Acquire(conn); + assertTrue(conn->refCount == 2, "Wrong refcount, got %u expected %u", conn->refCount, 2); + + metisConnection_Release(©); + assertTrue(conn->refCount == 1, "Wrong refcount, got %u expected %u", conn->refCount, 1); + + metisConnection_Release(&conn); +} + +LONGBOW_TEST_CASE(Global, metisConnection_Create_Destroy) +{ + MetisIoOperations *ops = longBowTestCase_GetClipBoardData(testCase); + MetisConnection *conn = metisConnection_Create(ops); + assertNotNull(conn, "Got null connection"); + assertTrue(conn->refCount == 1, "Wrong refcount, got %u expected %u", conn->refCount, 1); + + metisConnection_Release(&conn); + assertNull(conn, "Release did not null pointer"); + + // the mock in testrig_MetisIoOperations does not destroy the IoOperations on destroy + // so we can still look at the counters + assertTrue(((MockIoOperationsData *) metisIoOperations_GetClosure(ops))->destroyCount == 1, + "Destroy count is wrong, got %u expected %u", + ((MockIoOperationsData *) metisIoOperations_GetClosure(ops))->destroyCount, + 1); +} + +LONGBOW_TEST_CASE(Global, metisConnection_Send) +{ + MetisIoOperations *ops = longBowTestCase_GetClipBoardData(testCase); + MockIoOperationsData *data = metisIoOperations_GetClosure(ops); + + MetisConnection *conn = metisConnection_Create(ops); + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + + MetisMessage *message = metisMessage_CreateFromArray((uint8_t *) metisTestDataV1_Interest_AllFields, + sizeof(metisTestDataV1_Interest_AllFields), 111, 2, logger); + + metisConnection_Send(conn, message); + + assertTrue(data->sendCount == 1, "Send count wrong, got %u expected %u", data->sendCount, 1); + assertTrue(data->lastMessage == message, "Sent wrong message, got %p expected %p", (void *) data->lastMessage, (void *) message); + + metisMessage_Release(&message); + metisConnection_Release(&conn); + metisLogger_Release(&logger); +} + +LONGBOW_TEST_CASE(Global, metisConnection_GetConnectionId) +{ + MetisIoOperations *ops = longBowTestCase_GetClipBoardData(testCase); + MockIoOperationsData *data = metisIoOperations_GetClosure(ops); + + MetisConnection *conn = metisConnection_Create(ops); + unsigned testid = metisConnection_GetConnectionId(conn); + + assertTrue(testid == data->id, "Got wrong id, got %u expected %u", testid, data->id); + assertTrue(data->getConnectionIdCount == 1, "Wrong getConnectionIdCount, got %u expected %u", data->getConnectionIdCount, 1); + + metisConnection_Release(&conn); +} + +LONGBOW_TEST_CASE(Global, metisConnection_GetAddressPair) +{ + MetisIoOperations *ops = longBowTestCase_GetClipBoardData(testCase); + MockIoOperationsData *data = metisIoOperations_GetClosure(ops); + + MetisConnection *conn = metisConnection_Create(ops); + + unsigned beforeCount = data->getAddressPairCount; + const MetisAddressPair *pair = metisConnection_GetAddressPair(conn); + + assertTrue(metisAddressPair_Equals(pair, data->addressPair), "Got wrong address pair"); + assertTrue(data->getAddressPairCount == beforeCount + 1, "Wrong getAddressPairCount, got %u expected %u", data->getAddressPairCount, beforeCount + 1); + + metisConnection_Release(&conn); +} + +LONGBOW_TEST_CASE(Global, metisConnection_IsUp) +{ + MetisIoOperations *ops = longBowTestCase_GetClipBoardData(testCase); + MockIoOperationsData *data = metisIoOperations_GetClosure(ops); + + MetisConnection *conn = metisConnection_Create(ops); + + unsigned beforeCount = data->isUpCount; + bool isup = metisConnection_IsUp(conn); + + assertTrue(isup == data->isUp, "Got wrong isup, got %d expected %d", isup, data->isUp); + assertTrue(data->isUpCount == beforeCount + 1, "Wrong isUpCount, got %u expected %u", data->isUpCount, beforeCount + 1); + + metisConnection_Release(&conn); +} + +LONGBOW_TEST_CASE(Global, metisConnection_IsLocal) +{ + MetisIoOperations *ops = longBowTestCase_GetClipBoardData(testCase); + MockIoOperationsData *data = metisIoOperations_GetClosure(ops); + + MetisConnection *conn = metisConnection_Create(ops); + + unsigned beforeCount = data->isLocalCount; + bool islocal = metisConnection_IsLocal(conn); + + assertTrue(islocal == data->isLocal, "Got wrong islocal, got %d expected %d", islocal, data->isLocal); + assertTrue(data->isLocalCount == beforeCount + 1, "Wrong isLocalCount, got %u expected %u", data->isLocalCount, beforeCount + 1); + + metisConnection_Release(&conn); +} + + +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(metis_Connection); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/metis/ccnx/forwarder/metis/core/test/test_metis_ConnectionList.c b/metis/ccnx/forwarder/metis/core/test/test_metis_ConnectionList.c new file mode 100644 index 00000000..94518a9e --- /dev/null +++ b/metis/ccnx/forwarder/metis/core/test/test_metis_ConnectionList.c @@ -0,0 +1,159 @@ +/* + * 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 "../metis_ConnectionList.c" +#include <parc/algol/parc_SafeMemory.h> +#include "testrig_MetisIoOperations.h" +#include <LongBow/unit-test.h> + +LONGBOW_TEST_RUNNER(metis_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); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(metis_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(metis_ConnectionList) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, metisConnectionList_Append); + LONGBOW_RUN_TEST_CASE(Global, metisConnectionList_Create_Destroy); + + LONGBOW_RUN_TEST_CASE(Global, metisConnectionList_Get); + LONGBOW_RUN_TEST_CASE(Global, metisConnectionList_Length); +} + +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, metisConnectionList_Append) +{ + MetisIoOperations *ops = mockIoOperationsData_CreateSimple(1, 2, 3, true, true, true); + MetisConnection *connection = metisConnection_Create(ops); + + MetisConnectionList *list = metisConnectionList_Create(); + metisConnectionList_Append(list, connection); + metisConnection_Release(&connection); + + assertTrue(parcArrayList_Size(list->listOfConnections) == 1, + "Got wrong list size, got %zu expected %u", + parcArrayList_Size(list->listOfConnections), 1); + + metisConnectionList_Destroy(&list); + mockIoOperationsData_Destroy(&ops); +} + +LONGBOW_TEST_CASE(Global, metisConnectionList_Create_Destroy) +{ + MetisConnectionList *list = metisConnectionList_Create(); + assertNotNull(list, "Got null from Create"); + + metisConnectionList_Destroy(&list); + assertNull(list, "Destroy did not null the parameter"); +} + +LONGBOW_TEST_CASE(Global, metisConnectionList_Get) +{ + MetisIoOperations *ops = mockIoOperationsData_CreateSimple(1, 2, 3, true, true, true); + MetisConnection *connection = metisConnection_Create(ops); + + MetisConnectionList *list = metisConnectionList_Create(); + metisConnectionList_Append(list, connection); + + MetisConnection *test = metisConnectionList_Get(list, 0); + assertTrue(test == connection, + "Got wrong connection, got %p expected %p", + (void *) test, (void *) connection); + + metisConnection_Release(&connection); + metisConnectionList_Destroy(&list); + mockIoOperationsData_Destroy(&ops); +} + +LONGBOW_TEST_CASE(Global, metisConnectionList_Length) +{ + MetisIoOperations *ops = mockIoOperationsData_CreateSimple(1, 2, 3, true, true, true); + MetisConnection *connection = metisConnection_Create(ops); + + MetisConnectionList *list = metisConnectionList_Create(); + metisConnectionList_Append(list, connection); + + size_t length = metisConnectionList_Length(list); + assertTrue(length == 1, + "Got wrong list size, got %zu expected %u", + length, 1); + + metisConnection_Release(&connection); + metisConnectionList_Destroy(&list); + mockIoOperationsData_Destroy(&ops); +} + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, metisConnectionList_ArrayDestroyer); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Local, metisConnectionList_ArrayDestroyer) +{ + testUnimplemented(""); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metis_ConnectionList); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/metis/ccnx/forwarder/metis/core/test/test_metis_ConnectionManager.c b/metis/ccnx/forwarder/metis/core/test/test_metis_ConnectionManager.c new file mode 100644 index 00000000..b4550e44 --- /dev/null +++ b/metis/ccnx/forwarder/metis/core/test/test_metis_ConnectionManager.c @@ -0,0 +1,261 @@ +/* + * 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 "../metis_ConnectionManager.c" + +#include <LongBow/unit-test.h> + +LONGBOW_TEST_RUNNER(metis_ConnectionManager) +{ + // 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(metis_ConnectionManager) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(metis_ConnectionManager) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, metisConnectionManager_Create); + LONGBOW_RUN_TEST_CASE(Global, metisConnectionManager_Destroy); +} + +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, metisConnectionManager_Create) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_CASE(Global, metisConnectionManager_Destroy) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, metisConnectionManager_MessengerCallback); + LONGBOW_RUN_TEST_CASE(Local, metisConnectionManager_NotifyApplications); + LONGBOW_RUN_TEST_CASE(Local, metisConnectionManager_ProcessDownMissive); + LONGBOW_RUN_TEST_CASE(Local, metisConnectionManager_ProcessQueue); + LONGBOW_RUN_TEST_CASE(Local, metisConnectionManager_ProcessUpMissive); + LONGBOW_RUN_TEST_CASE(Local, metisConnectionManager_ProcessDestroyMissive); + + LONGBOW_RUN_TEST_CASE(Local, metisConnectionManager_ProcessCloseMissive_RemoveConnection); + LONGBOW_RUN_TEST_CASE(Local, metisConnectionManager_ProcessCloseMissive_RemoveRoutes); +} + +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, metisConnectionManager_MessengerCallback) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_CASE(Local, metisConnectionManager_NotifyApplications) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_CASE(Local, metisConnectionManager_ProcessDownMissive) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_CASE(Local, metisConnectionManager_ProcessQueue) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_CASE(Local, metisConnectionManager_ProcessUpMissive) +{ + testUnimplemented(""); +} + +typedef struct my_connection { + MetisAddressPair *addressPair; + unsigned connectionId; +} MyConnection; + +static const MetisAddressPair * +getAddressPair(const MetisIoOperations *ops) +{ + MyConnection *myconn = (MyConnection *) ops->context; + return myconn->addressPair; +} + +static unsigned +getConnectionId(const MetisIoOperations *ops) +{ + MyConnection *myconn = (MyConnection *) ops->context; + return myconn->connectionId; +} + +static void +myConnectionDestroy(MetisIoOperations **opsPtr) +{ + MetisIoOperations *ops = *opsPtr; + MyConnection *myconn = (MyConnection *) ops->context; + metisAddressPair_Release(&myconn->addressPair); + parcMemory_Deallocate((void **) &ops); + *opsPtr = NULL; +} + +static MetisConnection * +createConnection(unsigned connectionId) +{ + MyConnection *myconn = parcMemory_AllocateAndClear(sizeof(MyConnection)); + assertNotNull(myconn, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(MyConnection)); + CPIAddress *a = cpiAddress_CreateFromInterface(1); + myconn->addressPair = metisAddressPair_Create(a, a); + myconn->connectionId = connectionId; + + cpiAddress_Destroy(&a); + + MetisIoOperations *ops = parcMemory_AllocateAndClear(sizeof(MetisIoOperations)); + assertNotNull(ops, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(MetisIoOperations)); + memset(ops, 0, sizeof(MetisIoOperations)); + ops->context = myconn; + ops->destroy = myConnectionDestroy; + ops->getAddressPair = getAddressPair; + ops->getConnectionId = getConnectionId; + + MetisConnection *conn = metisConnection_Create(ops); + return conn; +} + +static void +addRoute(MetisForwarder *metis, const char *name, unsigned connectionId) +{ + CCNxName *uri = ccnxName_CreateFromURI(name); + CPIRouteEntry *route = cpiRouteEntry_Create(uri, connectionId, NULL, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, NULL, 1); + + metisForwarder_AddOrUpdateRoute(metis, route); + ccnxName_Release(&uri); +} + +/** + * We add a connection, then send a CLOSE message, make sure the connection + * is no longer in the connection table. + */ +LONGBOW_TEST_CASE(Local, metisConnectionManager_ProcessCloseMissive_RemoveConnection) +{ + unsigned connectionId = 1000; + + MetisForwarder *metis = metisForwarder_Create(NULL); + metisDispatcher_RunDuration(metisForwarder_GetDispatcher(metis), &((struct timeval) { 0, 10000 })); + + MetisConnection *conn = createConnection(connectionId); + metisConnectionTable_Add(metisForwarder_GetConnectionTable(metis), conn); + + metisDispatcher_RunDuration(metisForwarder_GetDispatcher(metis), &((struct timeval) { 0, 10000 })); + + // send close message + metisMessenger_Send(metisForwarder_GetMessenger(metis), metisMissive_Create(MetisMissiveType_ConnectionClosed, connectionId)); + metisDispatcher_RunDuration(metisForwarder_GetDispatcher(metis), &((struct timeval) { 0, 10000 })); + + // now make sure its gone + const MetisConnection *test = metisConnectionTable_FindById(metisForwarder_GetConnectionTable(metis), connectionId); + assertNull(test, "Return from connection table should be null, got %p\n", (const void *) test); + + metisForwarder_Destroy(&metis); +} + +/** + * We add a connection and a route that uses that connection, then send a CLOSE message, + * then make sure the connection is no longer in the routing table. + */ +LONGBOW_TEST_CASE(Local, metisConnectionManager_ProcessCloseMissive_RemoveRoutes) +{ + unsigned connectionId = 1001; + + MetisForwarder *metis = metisForwarder_Create(NULL); + metisDispatcher_RunDuration(metisForwarder_GetDispatcher(metis), &((struct timeval) { 0, 10000 })); + + MetisConnection *conn = createConnection(connectionId); + metisConnectionTable_Add(metisForwarder_GetConnectionTable(metis), conn); + + addRoute(metis, "lci:/foo/bar", connectionId); + + metisDispatcher_RunDuration(metisForwarder_GetDispatcher(metis), &((struct timeval) { 0, 10000 })); + + // send close message + metisMessenger_Send(metisForwarder_GetMessenger(metis), metisMissive_Create(MetisMissiveType_ConnectionClosed, connectionId)); + metisDispatcher_RunDuration(metisForwarder_GetDispatcher(metis), &((struct timeval) { 0, 10000 })); + + // now make sure its gone + MetisFibEntryList *fiblist = metisForwarder_GetFibEntries(metis); + for (size_t i = 0; i < metisFibEntryList_Length(fiblist); i++) { + MetisFibEntry *fibentry = metisFibEntryList_Get(fiblist, i); + assertTrue(metisFibEntry_NexthopCount(fibentry) == 0, "Wrong nexthop count, expected 0 got %zu", metisFibEntry_NexthopCount(fibentry)); + } + + metisForwarder_Destroy(&metis); +} + +LONGBOW_TEST_CASE(Local, metisConnectionManager_ProcessDestroyMissive) +{ + testUnimplemented(""); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metis_ConnectionManager); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/metis/ccnx/forwarder/metis/core/test/test_metis_ConnectionTable.c b/metis/ccnx/forwarder/metis/core/test/test_metis_ConnectionTable.c new file mode 100644 index 00000000..b55b6e67 --- /dev/null +++ b/metis/ccnx/forwarder/metis/core/test/test_metis_ConnectionTable.c @@ -0,0 +1,490 @@ +/* + * 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 "../metis_ConnectionTable.c" +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> + +#include "testrig_MetisIoOperations.h" + +static struct test_set_s { + unsigned localAddr; + unsigned remoteAddr; + unsigned id; + MetisIoOperations *ops; + MetisConnection *conn; +} test_set [] = { + { .localAddr = 1, .remoteAddr = 2, .id = 3, .ops = NULL }, + { .localAddr = 2, .remoteAddr = 1, .id = 4, .ops = NULL }, + { .localAddr = 7, .remoteAddr = 2, .id = 22, .ops = NULL }, + { .localAddr = 13, .remoteAddr = 2, .id = 102332, .ops = NULL }, + { .localAddr = 99, .remoteAddr = 2, .id = 99, .ops = NULL }, + { .localAddr = 3, .remoteAddr = 5, .id = 0xFFFFFFFF, .ops = NULL }, + { .localAddr = 0, .remoteAddr = 0, .id = 0, .ops = NULL } +}; + +// ============================================ + +LONGBOW_TEST_RUNNER(metis_ConnectionTable) +{ + // 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(CreateDestroy); + 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(metis_ConnectionTable) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(metis_ConnectionTable) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// ============================================ + +LONGBOW_TEST_FIXTURE(CreateDestroy) +{ + LONGBOW_RUN_TEST_CASE(CreateDestroy, metisConnectionTable_Create_Destroy); + LONGBOW_RUN_TEST_CASE(CreateDestroy, metisConnectionTable_Add); +} + +LONGBOW_TEST_FIXTURE_SETUP(CreateDestroy) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(CreateDestroy) +{ + 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(CreateDestroy, metisConnectionTable_Create_Destroy) +{ + MetisConnectionTable *table = metisConnectionTable_Create(); + metisConnectionTable_Destroy(&table); + + assertTrue(parcMemory_Outstanding() == 0, "Got memory imbalance on create/destroy: %u", parcMemory_Outstanding()); +} + +LONGBOW_TEST_CASE(CreateDestroy, metisConnectionTable_Add) +{ + MetisConnectionTable *table = metisConnectionTable_Create(); + MetisIoOperations *ops = mockIoOperationsData_CreateSimple(1, 2, 3, true, true, true); + MockIoOperationsData *data = metisIoOperations_GetClosure(ops); + + MetisConnection *conn = metisConnection_Create(ops); + + assertTrue(parcHashCodeTable_Length(table->storageTableById) == 0, + "storageTableById not empty at start of test, length %zu", + parcHashCodeTable_Length(table->storageTableById)); + + assertTrue(parcHashCodeTable_Length(table->indexByAddressPair) == 0, + "indexByAddressPair not empty at start of test, length %zu", + parcHashCodeTable_Length(table->indexByAddressPair)); + + metisConnectionTable_Add(table, conn); + + assertTrue(parcHashCodeTable_Length(table->storageTableById) == 1, + "Incorrect storage table size, expected %u got %zu", + 1, + parcHashCodeTable_Length(table->storageTableById)); + + assertTrue(parcHashCodeTable_Length(table->indexByAddressPair) == 1, + "Incorrect storage table size, expected %u got %zu", + 1, + parcHashCodeTable_Length(table->indexByAddressPair)); + metisConnectionTable_Destroy(&table); + + assertTrue(data->destroyCount == 1, "metisConnectionTable_Destroy did not call entry's destroyer"); + + mockIoOperationsData_Destroy(&ops); + assertTrue(parcMemory_Outstanding() == 0, "Got memory imbalance on create/destroy: %u", parcMemory_Outstanding()); +} + +// ============================================ + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, metisConnectionTable_FindByAddressPair); + LONGBOW_RUN_TEST_CASE(Global, metisConnectionTable_FindById); + LONGBOW_RUN_TEST_CASE(Global, metisConnectionTable_Remove); + LONGBOW_RUN_TEST_CASE(Global, metisConnectionTable_RemoveById); + +// LONGBOW_RUN_TEST_CASE(Global, metisConnectionTable_GetEntries); +} + +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, metisConnectionTable_FindByAddressPair) +{ + MetisConnectionTable *table = metisConnectionTable_Create(); + + // add the test set to the table + for (int i = 0; test_set[i].localAddr != 0; i++) { + test_set[i].ops = mockIoOperationsData_CreateSimple(test_set[i].localAddr, test_set[i].remoteAddr, test_set[i].id, true, true, true); + assertNotNull(test_set[i].ops, "Got null from testdata_CreateSimple index %d", i); + test_set[i].conn = metisConnection_Create(test_set[i].ops); + assertNotNull(test_set[i].conn, "Got null from metisConnection_Create index %d", i); + metisConnectionTable_Add(table, test_set[i].conn); + } + + + // now make sure we can find them all by their address pair + for (int i = 0; test_set[i].localAddr != 0; i++) { + const MetisAddressPair *pair = test_set[i].ops->getAddressPair(test_set[i].ops); + const MetisConnection *conn = metisConnectionTable_FindByAddressPair(table, pair); + assertTrue(conn == test_set[i].conn, + "id %u returned wrong pointer, expected %p got %p", + test_set[i].id, + (void *) test_set[i].conn, + (void *) conn); + } + + // cleanup and verify destructions + metisConnectionTable_Destroy(&table); + + for (int i = 0; test_set[i].localAddr != 0; i++) { + MockIoOperationsData *data = metisIoOperations_GetClosure(test_set[i].ops); + assertTrue(data->destroyCount == 1, "Did not destroy data element %d, count %u", i, data->destroyCount); + mockIoOperationsData_Destroy(&test_set[i].ops); + } +} + +LONGBOW_TEST_CASE(Global, metisConnectionTable_FindById) +{ + MetisConnectionTable *table = metisConnectionTable_Create(); + + // add the test set to the table + for (int i = 0; test_set[i].localAddr != 0; i++) { + test_set[i].ops = mockIoOperationsData_CreateSimple(test_set[i].localAddr, test_set[i].remoteAddr, test_set[i].id, true, true, true); + assertNotNull(test_set[i].ops, "Got null from testdata_CreateSimple index %d", i); + test_set[i].conn = metisConnection_Create(test_set[i].ops); + assertNotNull(test_set[i].conn, "Got null from metisConnection_Create index %d", i); + metisConnectionTable_Add(table, test_set[i].conn); + } + + + // now make sure we can find them all by their id + for (int i = 0; test_set[i].localAddr != 0; i++) { + const MetisConnection *conn = metisConnectionTable_FindById(table, test_set[i].id); + assertTrue(conn == test_set[i].conn, + "id %u returned wrong pointer, expected %p got %p", + test_set[i].id, + (void *) test_set[i].conn, + (void *) conn); + } + + // cleanup and verify destructions + metisConnectionTable_Destroy(&table); + + for (int i = 0; test_set[i].localAddr != 0; i++) { + MockIoOperationsData *data = metisIoOperations_GetClosure(test_set[i].ops); + assertTrue(data->destroyCount == 1, "Did not destroy data element %d, count %u", i, data->destroyCount); + mockIoOperationsData_Destroy(&test_set[i].ops); + } +} + +LONGBOW_TEST_CASE(Global, metisConnectionTable_Remove) +{ + MetisConnectionTable *table = metisConnectionTable_Create(); + + MetisIoOperations *ops = mockIoOperationsData_CreateSimple(1, 2, 3, true, true, true); + MetisConnection *conn = metisConnection_Create(ops); + metisConnectionTable_Add(table, conn); + + + // Check preconditions + assertTrue(parcHashCodeTable_Length(table->storageTableById) == 1, + "storageTableById wrong size, expected %u got %zu", + 1, + parcHashCodeTable_Length(table->storageTableById)); + + assertTrue(parcHashCodeTable_Length(table->indexByAddressPair) == 1, + "indexByAddressPair wrong size, expected %u got %zu", + 1, + parcHashCodeTable_Length(table->indexByAddressPair)); + + // test the operation + metisConnectionTable_Remove(table, conn); + + // check post conditions + assertTrue(parcHashCodeTable_Length(table->storageTableById) == 0, + "storageTableById wrong size, expected %u got %zu", + 0, + parcHashCodeTable_Length(table->storageTableById)); + + assertTrue(parcHashCodeTable_Length(table->indexByAddressPair) == 0, + "indexByAddressPair wrong size, expected %u got %zu", + 0, + parcHashCodeTable_Length(table->indexByAddressPair)); + + // cleanup + MockIoOperationsData *data = metisIoOperations_GetClosure(ops); + assertTrue(data->destroyCount == 1, "Remove did not destroy data, count %u", data->destroyCount); + mockIoOperationsData_Destroy(&ops); + metisConnectionTable_Destroy(&table); +} + +LONGBOW_TEST_CASE(Global, metisConnectionTable_RemoveById) +{ + MetisConnectionTable *table = metisConnectionTable_Create(); + + unsigned connid = 3; + + MetisIoOperations *ops = mockIoOperationsData_CreateSimple(1, 2, connid, true, true, true); + MetisConnection *conn = metisConnection_Create(ops); + metisConnectionTable_Add(table, conn); + + // Check preconditions + assertTrue(parcHashCodeTable_Length(table->storageTableById) == 1, + "storageTableById wrong size, expected %u got %zu", + 1, + parcHashCodeTable_Length(table->storageTableById)); + + assertTrue(parcHashCodeTable_Length(table->indexByAddressPair) == 1, + "indexByAddressPair wrong size, expected %u got %zu", + 1, + parcHashCodeTable_Length(table->indexByAddressPair)); + + // test the operation + metisConnectionTable_RemoveById(table, connid); + + + // check post conditions + assertTrue(parcHashCodeTable_Length(table->storageTableById) == 0, + "storageTableById wrong size, expected %u got %zu", + 0, + parcHashCodeTable_Length(table->storageTableById)); + + assertTrue(parcHashCodeTable_Length(table->indexByAddressPair) == 0, + "indexByAddressPair wrong size, expected %u got %zu", + 0, + parcHashCodeTable_Length(table->indexByAddressPair)); + + // cleanup + MockIoOperationsData *data = metisIoOperations_GetClosure(ops); + assertTrue(data->destroyCount == 1, "Remove did not destroy data, count %u", data->destroyCount); + mockIoOperationsData_Destroy(&ops); + metisConnectionTable_Destroy(&table); +} + +LONGBOW_TEST_CASE(Global, metisConnectionTable_GetEntries) +{ + MetisConnectionTable *table = metisConnectionTable_Create(); + + size_t count = 0; + // add the test set to the table + for (int i = 0; test_set[i].localAddr != 0; i++) { + test_set[i].ops = mockIoOperationsData_CreateSimple(test_set[i].localAddr, test_set[i].remoteAddr, test_set[i].id, true, true, true); + assertNotNull(test_set[i].ops, "Got null from testdata_CreateSimple index %d", i); + test_set[i].conn = metisConnection_Create(test_set[i].ops); + assertNotNull(test_set[i].conn, "Got null from metisConnection_Create index %d", i); + metisConnectionTable_Add(table, test_set[i].conn); + count++; + } + + MetisConnectionList *list = metisConnectionTable_GetEntries(table); + assertTrue(metisConnectionList_Length(list) == count, "List wrong size, expected %zu got %zu", count, metisConnectionList_Length(list)); + + // now verify each entry. The entries are not necessarily in the same order + for (int i = 0; i < count; i++) { + MetisConnection *test = metisConnectionList_Get(list, i); + const MetisAddressPair *test_pair = metisConnection_GetAddressPair(test); + const MetisAddressPair *truth_pair = test_set[i].ops->getAddressPair(test_set[i].ops); + assertTrue(metisAddressPair_Equals(test_pair, truth_pair), "Address pairs not equal, index %d", i); + } + + metisConnectionList_Destroy(&list); + for (int i = 0; test_set[i].localAddr != 0; i++) { + MockIoOperationsData *data = metisIoOperations_GetClosure(test_set[i].ops); + assertTrue(data->destroyCount == 1, "Did not destroy data element %d, count %u", i, data->destroyCount); + mockIoOperationsData_Destroy(&test_set[i].ops); + } +} + +// ============================================================================== + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, metisConnectionTable_AddressPairEquals_IsEqual); + LONGBOW_RUN_TEST_CASE(Local, metisConnectionTable_AddressPairEquals_IsNotEqual); + LONGBOW_RUN_TEST_CASE(Local, metisConnectionTable_AddressPairHashCode); + LONGBOW_RUN_TEST_CASE(Local, metisConnectionTable_ConnectionDestroyer); + LONGBOW_RUN_TEST_CASE(Local, metisConnectionTable_ConnectionIdDestroyer); + LONGBOW_RUN_TEST_CASE(Local, metisConnectionTable_ConnectionIdEquals_IsEqual); + LONGBOW_RUN_TEST_CASE(Local, metisConnectionTable_ConnectionIdEquals_IsNotEqual); + LONGBOW_RUN_TEST_CASE(Local, metisConnectionTable_ConnectionIdHashCode); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) { + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + + +LONGBOW_TEST_CASE(Local, metisConnectionTable_AddressPairEquals_IsEqual) +{ + CPIAddress *a1 = cpiAddress_CreateFromInterface(1); + CPIAddress *a2 = cpiAddress_CreateFromInterface(2); + MetisAddressPair *pair_a = metisAddressPair_Create(a1, a2); + + CPIAddress *b1 = cpiAddress_CreateFromInterface(1); + CPIAddress *b2 = cpiAddress_CreateFromInterface(2); + MetisAddressPair *pair_b = metisAddressPair_Create(b1, b2); + + bool success = metisConnectionTable_AddressPairEquals((void *) pair_a, (void *) pair_b); + assertTrue(success, "Equal address pairs do not compare"); + + metisAddressPair_Release(&pair_a); + metisAddressPair_Release(&pair_b); + cpiAddress_Destroy(&a1); + cpiAddress_Destroy(&a2); + cpiAddress_Destroy(&b1); + cpiAddress_Destroy(&b2); +} + +LONGBOW_TEST_CASE(Local, metisConnectionTable_AddressPairEquals_IsNotEqual) +{ + CPIAddress *a1 = cpiAddress_CreateFromInterface(1); + CPIAddress *a2 = cpiAddress_CreateFromInterface(2); + MetisAddressPair *pair_a = metisAddressPair_Create(a1, a2); + + CPIAddress *b1 = cpiAddress_CreateFromInterface(1); + CPIAddress *b2 = cpiAddress_CreateFromInterface(2); + MetisAddressPair *pair_b = metisAddressPair_Create(b2, b1); + + bool success = metisConnectionTable_AddressPairEquals((void *) pair_a, (void *) pair_b); + assertFalse(success, "Unequal address pairs compare as equal"); + + metisAddressPair_Release(&pair_a); + metisAddressPair_Release(&pair_b); + cpiAddress_Destroy(&a1); + cpiAddress_Destroy(&a2); + cpiAddress_Destroy(&b1); + cpiAddress_Destroy(&b2); +} + +LONGBOW_TEST_CASE(Local, metisConnectionTable_AddressPairHashCode) +{ + CPIAddress *a1 = cpiAddress_CreateFromInterface(1); + CPIAddress *a2 = cpiAddress_CreateFromInterface(2); + MetisAddressPair *pair_a = metisAddressPair_Create(a1, a2); + + HashCodeType truth = metisAddressPair_HashCode(pair_a); + HashCodeType hash = metisConnectionTable_AddressPairHashCode((void *) pair_a); + + assertTrue(truth == hash, "Incorrect hash code, expected %04"PRIX64 "got %04"PRIX64, truth, hash); + + metisAddressPair_Release(&pair_a); + cpiAddress_Destroy(&a1); + cpiAddress_Destroy(&a2); +} + +LONGBOW_TEST_CASE(Local, metisConnectionTable_ConnectionDestroyer) +{ + MetisIoOperations *ops = mockIoOperationsData_CreateSimple(1, 2, 3, true, true, true); + MetisConnection *conn = metisConnection_Create(ops); + MockIoOperationsData *data = metisIoOperations_GetClosure(ops); + + assertTrue(data->destroyCount == 0, "testdata_CreateSimple did not zero destroyCount"); + + metisConnectionTable_ConnectionDestroyer((void **) &conn); + + assertTrue(data->destroyCount == 1, "metisConnectionTable_ConnectionDestroyer did not call destroy on MetisIoOperations"); + mockIoOperationsData_Destroy(&ops); + + assertTrue(parcMemory_Outstanding() == 0, "Memory imbalance, expected 0 got %u", parcMemory_Outstanding()); +} + +LONGBOW_TEST_CASE(Local, metisConnectionTable_ConnectionIdDestroyer) +{ + unsigned *aptr = parcMemory_Allocate(sizeof(unsigned)); + assertNotNull(aptr, "parcMemory_Allocate(%zu) returned NULL", sizeof(unsigned)); + metisConnectionTable_ConnectionIdDestroyer((void **) &aptr); + assertNull(aptr, "destroyer did not null pointer"); + assertTrue(parcMemory_Outstanding() == 0, "Memory imbalance, expected 0 got %u", parcMemory_Outstanding()); +} + +LONGBOW_TEST_CASE(Local, metisConnectionTable_ConnectionIdEquals_IsEqual) +{ + unsigned a = 0x01020304; + unsigned b = 0x01020304; + + bool success = metisConnectionTable_ConnectionIdEquals(&a, &b); + assertTrue(success, "equal unsigned pointers do not compare"); +} + +LONGBOW_TEST_CASE(Local, metisConnectionTable_ConnectionIdEquals_IsNotEqual) +{ + unsigned a = 0x01020304; + unsigned b = 0x01020305; + + bool success = metisConnectionTable_ConnectionIdEquals(&a, &b); + assertFalse(success, "Unequal unsigned pointers compare as equal"); +} + +LONGBOW_TEST_CASE(Local, metisConnectionTable_ConnectionIdHashCode) +{ + unsigned a = 0x01020304; + + HashCodeType truth = parcHash32_Int32(a); + HashCodeType hash = metisConnectionTable_ConnectionIdHashCode(&a); + + assertTrue(truth == hash, "Incorrect hash code, expected %04"PRIX64 "got %04"PRIX64, truth, hash); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metis_ConnectionTable); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/metis/ccnx/forwarder/metis/core/test/test_metis_Dispatcher.c b/metis/ccnx/forwarder/metis/core/test/test_metis_Dispatcher.c new file mode 100644 index 00000000..3845d0d5 --- /dev/null +++ b/metis/ccnx/forwarder/metis/core/test/test_metis_Dispatcher.c @@ -0,0 +1,733 @@ +/* + * 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 "../metis_Dispatcher.c" +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> +#include <parc/algol/parc_EventQueue.h> +#include <parc/logging/parc_LogReporterTextStdout.h> + +#include <ccnx/forwarder/metis/core/metis_Forwarder.h> + +LONGBOW_TEST_RUNNER(metis_Dispatcher) +{ + // 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. +#ifdef PARC_MEMORY + // The CreateDestroy fixture diagnoses issues with the debug memory allocator, + // which will fail if that allocator is not in use. + LONGBOW_RUN_TEST_FIXTURE(CreateDestroy); +#endif + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(StreamBufferConnect); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(metis_Dispatcher) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(metis_Dispatcher) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// ================================================================================= +LONGBOW_TEST_FIXTURE(CreateDestroy) +{ + LONGBOW_RUN_TEST_CASE(CreateDestroy, metisDispatcher_Create_Destroy); + LONGBOW_RUN_TEST_CASE(CreateDestroy, metisDispatcher_Memory); +} + +LONGBOW_TEST_FIXTURE_SETUP(CreateDestroy) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(CreateDestroy) +{ + 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(CreateDestroy, metisDispatcher_Create_Destroy) +{ + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisDispatcher *dispatcher = metisDispatcher_Create(logger); + metisDispatcher_Destroy(&dispatcher); + metisLogger_Release(&logger); + assertTrue(parcSafeMemory_ReportAllocation(STDOUT_FILENO) == 0, "Got memory imbalance on create/destroy: %u", parcMemory_Outstanding()); +} + +/** + * Ensure that the dispatcher is using parc memory inside event scheduler + */ +LONGBOW_TEST_CASE(CreateDestroy, metisDispatcher_Memory) +{ + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisDispatcher *dispatcher = metisDispatcher_Create(logger); + size_t baseline = parcMemory_Outstanding(); + + PARCEventBuffer *buffer = parcEventBuffer_Create(); + + assertTrue(parcMemory_Outstanding() > baseline, + "parcEventBuffer_Create() did not increase parcMemory_Outstanding: baseline %zu now %u", + baseline, + parcMemory_Outstanding()); + + parcEventBuffer_Destroy(&buffer); + + assertTrue(parcMemory_Outstanding() == baseline, + "parcEventBuffer_Destroy() did reduce to baseline: baseline %zu now %u", + baseline, + parcMemory_Outstanding()); + + metisDispatcher_Destroy(&dispatcher); + metisLogger_Release(&logger); + + assertTrue(parcSafeMemory_ReportAllocation(STDOUT_FILENO) == 0, "Got memory imbalance on create/destroy: %u", parcMemory_Outstanding()); +} + +// ================================================================================= + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, metisDispatcher_CreateTimer_Oneshot); + LONGBOW_RUN_TEST_CASE(Global, metisDispatcher_CreateTimer_Periodic); + LONGBOW_RUN_TEST_CASE(Global, metisDispatcher_StopTimer); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisDispatcher *dispatcher = metisDispatcher_Create(logger); + metisLogger_Release(&logger); + + longBowTestCase_SetClipBoardData(testCase, dispatcher); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + MetisDispatcher *dispatcher = longBowTestCase_GetClipBoardData(testCase); + metisDispatcher_Destroy(&dispatcher); + + 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 void +timerCallback(int fd, PARCEventType which_event, void *user_data) +{ + assertTrue(which_event & PARCEventType_Timeout, "Event incorrect, expecting %X set, got %X", PARCEventType_Timeout, which_event); + (*(unsigned *) user_data)++; +} + +LONGBOW_TEST_CASE(Global, metisDispatcher_CreateTimer_Oneshot) +{ + MetisDispatcher *dispatcher = longBowTestCase_GetClipBoardData(testCase); + + unsigned timerCallbackCount = 0; + PARCEventTimer *event = metisDispatcher_CreateTimer(dispatcher, false, timerCallback, &timerCallbackCount); + assertNotNull(event, "Got null event from metisDispatcher_CreateTimer"); + + // 10 msec + struct timeval timeout = { 0, 10000 }; + metisDispatcher_StartTimer(dispatcher, event, &timeout); + + // run for 250 msec; + struct timeval runtime = { 0, 250000 }; + metisDispatcher_RunDuration(dispatcher, &runtime); + + assertTrue(timerCallbackCount == 1, "Incorrect timer callbacks, expected %u got %u", 1, timerCallbackCount); + metisDispatcher_DestroyTimerEvent(dispatcher, &event); +} + +LONGBOW_TEST_CASE(Global, metisDispatcher_CreateTimer_Periodic) +{ +#ifdef __ARMEL__ + testUnimplemented("Test not implemented on ARMEL, timers too inaccurate"); +#else + MetisDispatcher *dispatcher = longBowTestCase_GetClipBoardData(testCase); + + unsigned timerCallbackCount = 0; + PARCEventTimer *event = metisDispatcher_CreateTimer(dispatcher, true, timerCallback, &timerCallbackCount); + assertNotNull(event, "Got null event from metisDispatcher_CreateTimer"); + + // 10 msec + struct timeval timeout = { 0, 10000 }; + metisDispatcher_StartTimer(dispatcher, event, &timeout); + + // run for 255 msec. Use an offset time to run so its clear what we should be after + // the 25th event and before the 26th event. + + struct timeval runtime = { 0, 255000 }; + metisDispatcher_RunDuration(dispatcher, &runtime); + + // make sure it runs at least twice (is periodic). Could run as many as 25. + assertTrue(timerCallbackCount >= 2, "Incorrect timer callbacks, expected at least %u got %u", 2, timerCallbackCount); + metisDispatcher_DestroyTimerEvent(dispatcher, &event); +#endif +} + +LONGBOW_TEST_CASE(Global, metisDispatcher_StopTimer) +{ + MetisDispatcher *dispatcher = longBowTestCase_GetClipBoardData(testCase); + + unsigned timerCallbackCount = 0; + PARCEventTimer *event = metisDispatcher_CreateTimer(dispatcher, true, timerCallback, &timerCallbackCount); + assertNotNull(event, "Got null event from metisDispatcher_CreateTimer"); + + // 10 msec + struct timeval timeout = { 0, 10000 }; + metisDispatcher_StartTimer(dispatcher, event, &timeout); + + // run for 55 msec (5 events), then stop the timer and run another 55 msec + + struct timeval runtime = { 0, 55000 }; + metisDispatcher_RunDuration(dispatcher, &runtime); + + metisDispatcher_StopTimer(dispatcher, event); + metisDispatcher_RunDuration(dispatcher, &runtime); + + // not sure how many times it will fire, but it should not fire more than 5 times + assertTrue(timerCallbackCount <= 5, "Incorrect timer callbacks, expected no more than %u got %u", 5, timerCallbackCount); + metisDispatcher_DestroyTimerEvent(dispatcher, &event); +} + +// ================================================================================= + +typedef struct open_connection_state { +// MetisForwarder * metis; + MetisDispatcher *dispatcher; + + CPIAddress *a; + CPIAddress *b; + MetisAddressPair *pair; + size_t baselineMemoryBalance; + + // if serverSocket > 0, then its allocated + int serverSocket; + struct sockaddr *serverAddr; + socklen_t serverAddrLength; +} OpenConnectionState; + +static void +listenToInet(OpenConnectionState *ocs) +{ + struct sockaddr_in server; + memset(&server, 0, sizeof(server)); + server.sin_family = PF_INET; + server.sin_addr.s_addr = INADDR_ANY; + server.sin_port = INPORT_ANY; + + int fd = socket(PF_INET, SOCK_STREAM, 0); + assertFalse(fd < 0, "error on bind: (%d) %s", errno, strerror(errno)); + + // Set non-blocking flag + int flags = fcntl(fd, F_GETFL, NULL); + assertTrue(flags != -1, "fcntl failed to obtain file descriptor flags (%d)\n", errno); + int failure = fcntl(fd, F_SETFL, flags | O_NONBLOCK); + assertFalse(failure, "fcntl failed to set file descriptor flags (%d)\n", errno); + + failure = bind(fd, (struct sockaddr *) &server, sizeof(server)); + assertFalse(failure, "error on bind: (%d) %s", errno, strerror(errno)); + + failure = listen(fd, 16); + assertFalse(failure, "error on listen: (%d) %s", errno, strerror(errno)); + + ocs->serverSocket = fd; + ocs->serverAddrLength = sizeof(struct sockaddr_in); + ocs->serverAddr = parcMemory_Allocate(ocs->serverAddrLength); + assertNotNull(ocs->serverAddr, "parcMemory_Allocate(%u) returned NULL", ocs->serverAddrLength); + + failure = getsockname(fd, ocs->serverAddr, &ocs->serverAddrLength); + assertFalse(failure, "error on getsockname: (%d) %s", errno, strerror(errno)); +} + +static void +listenToInet6(OpenConnectionState *ocs) +{ + struct sockaddr_in6 server; + memset(&server, 0, sizeof(server)); + server.sin6_family = PF_INET6; + server.sin6_addr = in6addr_any; + server.sin6_port = INPORT_ANY; + + int fd = socket(PF_INET6, SOCK_STREAM, 0); + assertFalse(fd < 0, "error on bind: (%d) %s", errno, strerror(errno)); + + // Set non-blocking flag + int flags = fcntl(fd, F_GETFL, NULL); + assertTrue(flags != -1, "fcntl failed to obtain file descriptor flags (%d)\n", errno); + int failure = fcntl(fd, F_SETFL, flags | O_NONBLOCK); + assertFalse(failure, "fcntl failed to set file descriptor flags (%d)\n", errno); + + failure = bind(fd, (struct sockaddr *) &server, sizeof(server)); + assertFalse(failure, "error on bind: (%d) %s", errno, strerror(errno)); + + failure = listen(fd, 16); + assertFalse(failure, "error on listen: (%d) %s", errno, strerror(errno)); + + ocs->serverSocket = fd; + ocs->serverAddrLength = sizeof(struct sockaddr_in6); + ocs->serverAddr = parcMemory_Allocate(ocs->serverAddrLength); + assertNotNull(ocs->serverAddr, "parcMemory_Allocate(%u) returned NULL", ocs->serverAddrLength); + + failure = getsockname(fd, ocs->serverAddr, &ocs->serverAddrLength); + assertFalse(failure, "error on getsockname: (%d) %s", errno, strerror(errno)); +} + +LONGBOW_TEST_FIXTURE(StreamBufferConnect) +{ + // -------- + // these two tests will cause assertions + LONGBOW_RUN_TEST_CASE(StreamBufferConnect, metisDispatcher_StreamBufferConnect_Invalid); + LONGBOW_RUN_TEST_CASE(StreamBufferConnect, metisDispatcher_StreamBufferConnect_DifferentTypes); + // -------- + + LONGBOW_RUN_TEST_CASE(StreamBufferConnect, metisDispatcher_StreamBufferConnect_INET); + LONGBOW_RUN_TEST_CASE(StreamBufferConnect, metisDispatcher_StreamBufferConnect_INET6); + + + LONGBOW_RUN_TEST_CASE(StreamBufferConnect, metisDispatcher_StreamBufferConnect_INET_Success); + LONGBOW_RUN_TEST_CASE(StreamBufferConnect, metisDispatcher_StreamBufferConnect_INET_Failure); + + LONGBOW_RUN_TEST_CASE(StreamBufferConnect, metisDispatcher_StreamBufferConnect_INET6_Success); + LONGBOW_RUN_TEST_CASE(StreamBufferConnect, metisDispatcher_StreamBufferConnect_INET6_Failure); + + LONGBOW_RUN_TEST_CASE(StreamBufferConnect, metisDispatcher_StreamBufferBindAndConnect_BindFail); + LONGBOW_RUN_TEST_CASE(StreamBufferConnect, metisDispatcher_StreamBufferBindAndConnect_BindOk_ConnectFail); + LONGBOW_RUN_TEST_CASE(StreamBufferConnect, metisDispatcher_StreamBufferBindAndConnect_BindOk_ConnectOk); +} + +LONGBOW_TEST_FIXTURE_SETUP(StreamBufferConnect) +{ + size_t baselineMemoryBalance = parcMemory_Outstanding(); + + OpenConnectionState *ocs = parcMemory_AllocateAndClear(sizeof(OpenConnectionState)); + assertNotNull(ocs, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(OpenConnectionState)); + memset(ocs, 0, sizeof(OpenConnectionState)); + + longBowTestCase_SetClipBoardData(testCase, ocs); + + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + ocs->dispatcher = metisDispatcher_Create(logger); + metisLogger_Release(&logger); + ocs->baselineMemoryBalance = baselineMemoryBalance; + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(StreamBufferConnect) +{ + OpenConnectionState *ocs = longBowTestCase_GetClipBoardData(testCase); + metisDispatcher_Destroy(&ocs->dispatcher); + + if (ocs->a) { + cpiAddress_Destroy(&ocs->a); + } + + if (ocs->b) { + cpiAddress_Destroy(&ocs->b); + } + + if (ocs->pair) { + metisAddressPair_Release(&ocs->pair); + } + + if (ocs->serverSocket > 0) { + close(ocs->serverSocket); + } + + if (ocs->serverAddr) { + parcMemory_Deallocate((void **) &(ocs->serverAddr)); + } + + size_t baselineMemoryBalance = ocs->baselineMemoryBalance; + parcMemory_Deallocate((void **) &ocs); + + if (parcMemory_Outstanding() != baselineMemoryBalance) { + parcSafeMemory_ReportAllocation(STDOUT_FILENO); + assertTrue(parcMemory_Outstanding() == ocs->baselineMemoryBalance, + "memory imbalance in %s: exepcted %zu got %u", + longBowTestCase_GetName(testCase), + baselineMemoryBalance, + parcMemory_Outstanding()); + } + + + return LONGBOW_STATUS_SUCCEEDED; +} + +/** + * Tests invalid protocol family + */ +LONGBOW_TEST_CASE_EXPECTS(StreamBufferConnect, metisDispatcher_StreamBufferConnect_Invalid, .event = &LongBowTrapIllegalValue) +{ + OpenConnectionState *ocs = longBowTestCase_GetClipBoardData(testCase); + ocs->a = cpiAddress_CreateFromInterface(1); + ocs->b = cpiAddress_CreateFromInterface(2); + ocs->pair = metisAddressPair_Create(ocs->a, ocs->b); + + // this will throw a trap + fprintf(stderr, "\n\nTHIS IS NOT AN ERROR, EXPECTED TRAP: Assertion Illegal\n\n"); + metisDispatcher_StreamBufferConnect(ocs->dispatcher, ocs->pair); +} + +/** + * Tests different protocol families + */ +LONGBOW_TEST_CASE_EXPECTS(StreamBufferConnect, metisDispatcher_StreamBufferConnect_DifferentTypes, .event = &LongBowAssertEvent) +{ + OpenConnectionState *ocs = longBowTestCase_GetClipBoardData(testCase); + ocs->a = cpiAddress_CreateFromInet(&((struct sockaddr_in) { .sin_family = PF_INET })); + ocs->b = cpiAddress_CreateFromInet6(&((struct sockaddr_in6) { .sin6_family = PF_INET6 })); + ocs->pair = metisAddressPair_Create(ocs->a, ocs->b); + + // this will throw a trap + fprintf(stderr, "\n\nTHIS IS NOT AN ERROR, EXPECTED ASSERTION: Assertion cpiAddress_GetType...\n\n"); + metisDispatcher_StreamBufferConnect(ocs->dispatcher, ocs->pair); +} + +/** + * Use a port that is already in use + */ +LONGBOW_TEST_CASE(StreamBufferConnect, metisDispatcher_StreamBufferBindAndConnect_BindFail) +{ + OpenConnectionState *ocs = longBowTestCase_GetClipBoardData(testCase); + listenToInet(ocs); + + PARCEventQueue *buffer = parcEventQueue_Create(ocs->dispatcher->Base, -1, PARCEventQueueOption_CloseOnFree); + + // use the server address for our bind address. will cause a failure. + bool success = metisDispatcher_StreamBufferBindAndConnect(ocs->dispatcher, buffer, + ocs->serverAddr, ocs->serverAddrLength, + ocs->serverAddr, ocs->serverAddrLength); + parcEventQueue_Destroy(&buffer); + assertFalse(success, "metisDispatcher_StreamBufferBindAndConnect succedded with bind to in use address"); +} + +/** + * Good bind address, but bad connect to address + */ +LONGBOW_TEST_CASE(StreamBufferConnect, metisDispatcher_StreamBufferBindAndConnect_BindOk_ConnectFail) +{ + OpenConnectionState *ocs = longBowTestCase_GetClipBoardData(testCase); + + struct sockaddr_in goodAddress; + memset(&goodAddress, 0, sizeof(goodAddress)); + goodAddress.sin_family = PF_INET; + goodAddress.sin_addr.s_addr = INADDR_ANY; + goodAddress.sin_port = INPORT_ANY; + + struct sockaddr_in badAddress; + memset(&badAddress, 0xFF, sizeof(badAddress)); + badAddress.sin_family = PF_INET; + + PARCEventQueue *buffer = parcEventQueue_Create(ocs->dispatcher->Base, -1, PARCEventQueueOption_CloseOnFree); + + // use the server address for our bind address. will cause a failure. + bool success = metisDispatcher_StreamBufferBindAndConnect(ocs->dispatcher, buffer, + (struct sockaddr *) &goodAddress, sizeof(goodAddress), + (struct sockaddr *) &badAddress, sizeof(badAddress)); + + parcEventQueue_Destroy(&buffer); + assertFalse(success, "metisDispatcher_StreamBufferBindAndConnect succedded with bind to in use address"); +} + +/** + * Everything good, should succeed! + */ +LONGBOW_TEST_CASE(StreamBufferConnect, metisDispatcher_StreamBufferBindAndConnect_BindOk_ConnectOk) +{ + OpenConnectionState *ocs = longBowTestCase_GetClipBoardData(testCase); + listenToInet(ocs); + + struct sockaddr_in goodAddress; + memset(&goodAddress, 0, sizeof(goodAddress)); + goodAddress.sin_family = PF_INET; + goodAddress.sin_addr.s_addr = INADDR_ANY; + goodAddress.sin_port = INPORT_ANY; + + PARCEventQueue *buffer = parcEventQueue_Create(ocs->dispatcher->Base, -1, PARCEventQueueOption_CloseOnFree); + + // use the server address for our bind address. will cause a failure. + bool success = metisDispatcher_StreamBufferBindAndConnect(ocs->dispatcher, buffer, + (struct sockaddr *) &goodAddress, sizeof(goodAddress), + ocs->serverAddr, ocs->serverAddrLength); + + parcEventQueue_Destroy(&buffer); + assertTrue(success, "metisDispatcher_StreamBufferBindAndConnect did not succeed with good addresses"); +} + +LONGBOW_TEST_CASE(StreamBufferConnect, metisDispatcher_StreamBufferConnect_INET_Success) +{ + OpenConnectionState *ocs = longBowTestCase_GetClipBoardData(testCase); + listenToInet(ocs); + + uint16_t localPort = 9698; + printf("local port = %u\n", localPort); + + // Connection "from" will use localPort as the local port number + struct sockaddr_in goodLocalAddress; + memset(&goodLocalAddress, 0, sizeof(goodLocalAddress)); + goodLocalAddress.sin_family = PF_INET; + goodLocalAddress.sin_addr.s_addr = INADDR_ANY; + goodLocalAddress.sin_port = htons(localPort); + + ocs->a = cpiAddress_CreateFromInet(&goodLocalAddress); + + // ocs->serverAddr will have "0.0.0.0" as the address, so need to create + // something to 127.0.0.1 + struct sockaddr_in goodRemoteAddress; + memset(&goodRemoteAddress, 0, sizeof(goodRemoteAddress)); + goodRemoteAddress.sin_family = PF_INET; + goodRemoteAddress.sin_port = ((struct sockaddr_in *) ocs->serverAddr)->sin_port; + inet_pton(AF_INET, "127.0.0.1", &(goodRemoteAddress.sin_addr)); + + ocs->b = cpiAddress_CreateFromInet(&goodRemoteAddress); + + PARCEventQueue *result = metisDispatcher_StreamBufferConnect_INET(ocs->dispatcher, ocs->a, ocs->b); + + assertNotNull(result, "result buffer should be non-null for good local bind address 0.0.0.0 port %u", localPort) { + int res; + res = system("netstat -an -p tcp"); + assertTrue(res != -1, "Error on system call"); + res = system("ps -el"); + assertTrue(res != -1, "Error on system call"); + } + + // turn the crank a few times, then accept and make sure the bind address is correct + metisDispatcher_RunDuration(ocs->dispatcher, &((struct timeval) { 0, 1000 })); + + struct sockaddr_in clientAddr; + socklen_t clientAddrLen = sizeof(struct sockaddr_in); + int clientfd = accept(ocs->serverSocket, (struct sockaddr *) &clientAddr, &clientAddrLen); + assertFalse(clientfd < 0, "Error on accept: (%d) %s", errno, strerror(errno)); + + assertTrue(clientAddr.sin_port == goodLocalAddress.sin_port, + "Ports do not match, expecting %u got %u", + htons(goodLocalAddress.sin_port), + htons(clientAddr.sin_port)); + + close(clientfd); + metisDispatcher_RunCount(ocs->dispatcher, 1); + metisStreamBuffer_Destroy(&result); + metisDispatcher_RunCount(ocs->dispatcher, 1); +} + +/** + * Pass in a bad local address for the bind, will cause failure. + * should receive NULL back from call + */ +LONGBOW_TEST_CASE(StreamBufferConnect, metisDispatcher_StreamBufferConnect_INET_Failure) +{ + // This test only works on OSX, as linux will accept the 0xFFFFFFF address as localhost +#if !defined(__APPLE__) + testUnimplemented("Platform not supported"); +#else + OpenConnectionState *ocs = longBowTestCase_GetClipBoardData(testCase); + listenToInet(ocs); + + struct sockaddr_in badAddress; + memset(&badAddress, 0xFF, sizeof(badAddress)); + badAddress.sin_family = PF_INET; + + ocs->a = cpiAddress_CreateFromInet(&badAddress); + ocs->b = cpiAddress_CreateFromInet((struct sockaddr_in *) ocs->serverAddr); + + // use the server address for our bind address. will cause a failure. + PARCEventQueue *result = metisDispatcher_StreamBufferConnect_INET(ocs->dispatcher, ocs->a, ocs->b); + + assertNull(result, "result buffer should be null for bad local address"); +#endif +} + +LONGBOW_TEST_CASE(StreamBufferConnect, metisDispatcher_StreamBufferConnect_INET6_Success) +{ + OpenConnectionState *ocs = longBowTestCase_GetClipBoardData(testCase); + listenToInet6(ocs); + + struct sockaddr_in6 goodLocalAddress; + memset(&goodLocalAddress, 0, sizeof(goodLocalAddress)); + goodLocalAddress.sin6_family = PF_INET6; + goodLocalAddress.sin6_addr = in6addr_any; + goodLocalAddress.sin6_port = INPORT_ANY; + + ocs->a = cpiAddress_CreateFromInet6(&goodLocalAddress); + + // ocs->serverAddr will have "0.0.0.0" as the address, so need to create + // something to 127.0.0.1 + struct sockaddr_in6 goodRemoteAddress; + memset(&goodRemoteAddress, 0, sizeof(goodRemoteAddress)); + goodRemoteAddress.sin6_family = PF_INET6; + goodRemoteAddress.sin6_port = ((struct sockaddr_in6 *) ocs->serverAddr)->sin6_port; + inet_pton(AF_INET6, "::1", &(goodRemoteAddress.sin6_addr)); + + ocs->b = cpiAddress_CreateFromInet6(&goodRemoteAddress); + + PARCEventQueue *result = metisDispatcher_StreamBufferConnect_INET6(ocs->dispatcher, ocs->a, ocs->b); + + assertNotNull(result, "result buffer should be non-null for good local address"); + + + metisStreamBuffer_Destroy(&result); +} + +/** + * Pass in a bad local address for the bind, will cause failure. + * should receive NULL back from call + */ +LONGBOW_TEST_CASE(StreamBufferConnect, metisDispatcher_StreamBufferConnect_INET6_Failure) +{ + OpenConnectionState *ocs = longBowTestCase_GetClipBoardData(testCase); + listenToInet6(ocs); + + struct sockaddr_in6 badAddress; + memset(&badAddress, 0xFF, sizeof(badAddress)); + badAddress.sin6_family = PF_INET6; + + ocs->a = cpiAddress_CreateFromInet6(&badAddress); + ocs->b = cpiAddress_CreateFromInet6((struct sockaddr_in6 *) ocs->serverAddr); + + // use the server address for our bind address. will cause a failure. + PARCEventQueue *result = metisDispatcher_StreamBufferConnect_INET6(ocs->dispatcher, ocs->a, ocs->b); + + assertNull(result, "result buffer should be null for bad local address"); +} + +LONGBOW_TEST_CASE(StreamBufferConnect, metisDispatcher_StreamBufferConnect_INET) +{ + OpenConnectionState *ocs = longBowTestCase_GetClipBoardData(testCase); + listenToInet(ocs); + + struct sockaddr_in goodLocalAddress; + memset(&goodLocalAddress, 0, sizeof(goodLocalAddress)); + goodLocalAddress.sin_family = PF_INET; + goodLocalAddress.sin_addr.s_addr = INADDR_ANY; + goodLocalAddress.sin_port = INPORT_ANY; + + ocs->a = cpiAddress_CreateFromInet(&goodLocalAddress); + + // ocs->serverAddr will have "0.0.0.0" as the address, so need to create + // something to 127.0.0.1 + struct sockaddr_in goodRemoteAddress; + memset(&goodRemoteAddress, 0, sizeof(goodRemoteAddress)); + goodRemoteAddress.sin_family = PF_INET; + goodRemoteAddress.sin_port = ((struct sockaddr_in *) ocs->serverAddr)->sin_port; + inet_pton(AF_INET, "127.0.0.1", &(goodRemoteAddress.sin_addr)); + + ocs->b = cpiAddress_CreateFromInet(&goodRemoteAddress); + + MetisAddressPair *pair = metisAddressPair_Create(ocs->a, ocs->b); + PARCEventQueue *result = metisDispatcher_StreamBufferConnect(ocs->dispatcher, pair); + metisAddressPair_Release(&pair); + assertNotNull(result, "result buffer should be non-null for good local address"); + metisStreamBuffer_Destroy(&result); +} + +LONGBOW_TEST_CASE(StreamBufferConnect, metisDispatcher_StreamBufferConnect_INET6) +{ + OpenConnectionState *ocs = longBowTestCase_GetClipBoardData(testCase); + listenToInet6(ocs); + + struct sockaddr_in6 goodLocalAddress; + memset(&goodLocalAddress, 0, sizeof(goodLocalAddress)); + goodLocalAddress.sin6_family = PF_INET6; + goodLocalAddress.sin6_addr = in6addr_any; + goodLocalAddress.sin6_port = INPORT_ANY; + + ocs->a = cpiAddress_CreateFromInet6(&goodLocalAddress); + + // ocs->serverAddr will have "0.0.0.0" as the address, so need to create + // something to 127.0.0.1 + struct sockaddr_in6 goodRemoteAddress; + memset(&goodRemoteAddress, 0, sizeof(goodRemoteAddress)); + goodRemoteAddress.sin6_family = PF_INET6; + goodRemoteAddress.sin6_port = ((struct sockaddr_in6 *) ocs->serverAddr)->sin6_port; + inet_pton(AF_INET6, "::1", &(goodRemoteAddress.sin6_addr)); + + ocs->b = cpiAddress_CreateFromInet6(&goodRemoteAddress); + + MetisAddressPair *pair = metisAddressPair_Create(ocs->a, ocs->b); + PARCEventQueue *result = metisDispatcher_StreamBufferConnect(ocs->dispatcher, pair); + metisAddressPair_Release(&pair); + + assertNotNull(result, "result buffer should be non-null for good local address"); + + metisStreamBuffer_Destroy(&result); +} + +// ================================================================================= + +LONGBOW_TEST_FIXTURE(Local) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisDispatcher *dispatcher = metisDispatcher_Create(logger); + metisLogger_Release(&logger); + longBowTestCase_SetClipBoardData(testCase, dispatcher); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + MetisDispatcher *dispatcher = longBowTestCase_GetClipBoardData(testCase); + metisDispatcher_Destroy(&dispatcher); + + if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) { + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metis_Dispatcher); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/metis/ccnx/forwarder/metis/core/test/test_metis_Forwarder.c b/metis/ccnx/forwarder/metis/core/test/test_metis_Forwarder.c new file mode 100644 index 00000000..b5f99594 --- /dev/null +++ b/metis/ccnx/forwarder/metis/core/test/test_metis_Forwarder.c @@ -0,0 +1,241 @@ +/* + * 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 "../metis_Forwarder.c" +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> + +LONGBOW_TEST_RUNNER(metis_Forwarder) +{ + // 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(metis_Forwarder) +{ + 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(metis_Forwarder) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, byteArrayToUnsignedLong); + LONGBOW_RUN_TEST_CASE(Global, metisForwarder_Create); + LONGBOW_RUN_TEST_CASE(Global, metisForwarder_Destroy); + LONGBOW_RUN_TEST_CASE(Global, metisForwarder_GetDispatcher); + LONGBOW_RUN_TEST_CASE(Global, metisForwarder_GetMessenger); + LONGBOW_RUN_TEST_CASE(Global, metisForwarder_GetNextConnectionId); + LONGBOW_RUN_TEST_CASE(Global, metisForwarder_GetTicks); + LONGBOW_RUN_TEST_CASE(Global, metisForwarder_Log); + LONGBOW_RUN_TEST_CASE(Global, metisForwarder_Receive); + LONGBOW_RUN_TEST_CASE(Global, metis_run); + LONGBOW_RUN_TEST_CASE(Global, metis_stop); + + + LONGBOW_RUN_TEST_CASE(Global, metisForwarder_NanosToTicks_1sec); + LONGBOW_RUN_TEST_CASE(Global, metisForwarder_NanosToTicks_1msec); + LONGBOW_RUN_TEST_CASE(Global, metisForwarder_NanosToTicks_LessThanHz); + + LONGBOW_RUN_TEST_CASE(Global, metisForwarder_TicksToNanos_1sec); +} + +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, byteArrayToUnsignedLong) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, metisForwarder_Create) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, metisForwarder_Destroy) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, metisForwarder_GetDispatcher) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, metisForwarder_GetMessenger) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, metisForwarder_GetNextConnectionId) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, metisForwarder_GetTicks) +{ + MetisForwarder *metis = metisForwarder_Create(NULL); + MetisDispatcher *dispatcher = metisForwarder_GetDispatcher(metis); + + int msec = 50; + struct timeval duration = { 0, msec * 1000 }; + + // run for a bit to get things primed + metisDispatcher_RunDuration(dispatcher, &duration); + + MetisTicks t0 = metisForwarder_GetTicks(metis); + metisDispatcher_RunDuration(dispatcher, &duration); + MetisTicks t1 = metisForwarder_GetTicks(metis); + + int64_t tickDelta = (int64_t) (t1 - t0); + int64_t tickError = llabs(msec - tickDelta); + + metisForwarder_Destroy(&metis); + + printf("tickError = %" PRId64 "\n", tickError); + + // Test we're somewhere in the ballpark, betwen 40msec - 60msec + assertTrue(tickError <= 10, "tickError %" PRId64 + " (tickDelta %" PRId64 ")", + tickError, tickDelta); + +} + +LONGBOW_TEST_CASE(Global, metisForwarder_Log) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, metisForwarder_Receive) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, metis_run) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, metis_stop) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, metisForwarder_NanosToTicks_1sec) +{ + // 1 second + uint64_t nanos = 1000000000ULL; + MetisTicks t = metisForwarder_NanosToTicks(nanos); + + assertTrue(t == METISHZ, "1 second in nanos did not equal METISHZ, expected %d, got %" PRIu64, METISHZ, t); +} + +LONGBOW_TEST_CASE(Global, metisForwarder_NanosToTicks_1msec) +{ + // 1 second + uint64_t nanos = 1000000ULL; + MetisTicks t = metisForwarder_NanosToTicks(nanos); + MetisTicks expected = METISHZ / 1000; + if (expected == 0) { + expected = 1; + } + + assertTrue(t == expected, "1 msec in nanos did not equal METISHZ/1000, expected %" PRIu64 ", got %" PRIu64, expected, t); +} + +LONGBOW_TEST_CASE(Global, metisForwarder_NanosToTicks_LessThanHz) +{ + // 1 second + uint64_t nanos = 1ULL; + MetisTicks t = metisForwarder_NanosToTicks(nanos); + MetisTicks expected = 1; + + assertTrue(t == expected, "1 nsec in nanos did not equal 1, expected %" PRIu64 ", got %" PRIu64, expected, t); +} + +LONGBOW_TEST_CASE(Global, metisForwarder_TicksToNanos_1sec) +{ + MetisTicks t = METISHZ; + uint64_t expected = ((1000000000ULL) * t / METISHZ); + + uint64_t nanos = metisForwarder_TicksToNanos(t); + assertTrue(nanos == expected, "METISHZ ticks does not equal 1sec, expected %" PRIu64 ", got %" PRIu64, expected, nanos); +} + +// ====================================================================== + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, metisForwarder_Seed); + LONGBOW_RUN_TEST_CASE(Local, signal_cb); +} + +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, metisForwarder_Seed) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Local, signal_cb) +{ + testUnimplemented("This test is unimplemented"); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metis_Forwarder); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/metis/ccnx/forwarder/metis/core/test/test_metis_Logger.c b/metis/ccnx/forwarder/metis/core/test/test_metis_Logger.c new file mode 100644 index 00000000..4b62b1d6 --- /dev/null +++ b/metis/ccnx/forwarder/metis/core/test/test_metis_Logger.c @@ -0,0 +1,222 @@ +/* + * 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 "../metis_Logger.c" +#include <stdio.h> +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> + +LONGBOW_TEST_RUNNER(metis_Logger) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(metis_Logger) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(metis_Logger) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// ========================================================== + +/* + * _testWritter will vsprintf to this buffer + */ +#define _logLength 1024 +static char _lastLogMessage[_logLength]; + +static int +_testWriter(const char *message) +{ + int written = 0; + written = snprintf(_lastLogMessage, _logLength, "%s", message); + return written; +} + +static PARCLogReporter * +_testWriter_Acquire(const PARCLogReporter *reporter) +{ + return parcObject_Acquire(reporter); +} + +static void +_testWriter_Release(PARCLogReporter **reporterPtr) +{ + parcObject_Release((void **) reporterPtr); +} + +static void +_testWriter_Report(PARCLogReporter *reporter, const PARCLogEntry *entry) +{ + char *string = parcLogEntry_ToString(entry); + _testWriter(string); + parcMemory_Deallocate((void **) &string); +} + +static PARCLogReporter * +_testWriter_Create(void) +{ + return parcLogReporter_Create(_testWriter_Acquire, _testWriter_Release, _testWriter_Report, NULL); +} + +// ========================================================== + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, metisLogger_FacilityString_Found); + LONGBOW_RUN_TEST_CASE(Global, metisLogger_FacilityString_NotFound); + LONGBOW_RUN_TEST_CASE(Global, metisLogger_Create); + LONGBOW_RUN_TEST_CASE(Global, metisLogger_Acquire); + LONGBOW_RUN_TEST_CASE(Global, metisLogger_SetLogLevel); + LONGBOW_RUN_TEST_CASE(Global, metisLogger_IsLoggable_True); + LONGBOW_RUN_TEST_CASE(Global, metisLogger_IsLoggable_False); + LONGBOW_RUN_TEST_CASE(Global, metisLogger_Log_IsLoggable); + LONGBOW_RUN_TEST_CASE(Global, metisLogger_Log_IsNotLoggable); +} + +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, metisLogger_FacilityString_Found) +{ + for (MetisLoggerFacility i = 0; i < MetisLoggerFacility_END; i++) { + const char *test = metisLogger_FacilityString(i); + assertNotNull(test, "Got null string for facility %d", i); + } +} + +LONGBOW_TEST_CASE(Global, metisLogger_FacilityString_NotFound) +{ + const char *test = metisLogger_FacilityString(1000); + assertTrue(strcmp(test, "Unknown") == 0, "Got wrong string for unknown facility"); +} + +LONGBOW_TEST_CASE(Global, metisLogger_Create) +{ + PARCLogReporter *reporter = _testWriter_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + + metisLogger_Release(&logger); +} + +LONGBOW_TEST_CASE(Global, metisLogger_Acquire) +{ + PARCLogReporter *reporter = _testWriter_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + + MetisLogger *copy = metisLogger_Acquire(logger); + metisLogger_Release(&logger); + metisLogger_Release(©); +} + +LONGBOW_TEST_CASE(Global, metisLogger_SetLogLevel) +{ + PARCLogReporter *reporter = _testWriter_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + + metisLogger_SetLogLevel(logger, MetisLoggerFacility_IO, PARCLogLevel_Off); + + PARCLogLevel test = parcLog_GetLevel(logger->loggerArray[MetisLoggerFacility_IO]); + assertTrue(test == PARCLogLevel_Off, "wrong log level, expected %d got %d", PARCLogLevel_Off, test); + metisLogger_Release(&logger); +} + +LONGBOW_TEST_CASE(Global, metisLogger_IsLoggable_True) +{ + PARCLogReporter *reporter = _testWriter_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + + metisLogger_SetLogLevel(logger, MetisLoggerFacility_IO, PARCLogLevel_Warning); + bool isLoggable = metisLogger_IsLoggable(logger, MetisLoggerFacility_IO, PARCLogLevel_Warning); + assertTrue(isLoggable, "Did not get true for isLoggable when expecting true"); + metisLogger_Release(&logger); +} + +LONGBOW_TEST_CASE(Global, metisLogger_IsLoggable_False) +{ + PARCLogReporter *reporter = _testWriter_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + + metisLogger_SetLogLevel(logger, MetisLoggerFacility_IO, PARCLogLevel_Warning); + bool isLoggable = metisLogger_IsLoggable(logger, MetisLoggerFacility_IO, PARCLogLevel_Debug); + assertFalse(isLoggable, "Logging debug to warning facility should have been false"); + metisLogger_Release(&logger); +} + +LONGBOW_TEST_CASE(Global, metisLogger_Log_IsLoggable) +{ + PARCLogReporter *reporter = _testWriter_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + + metisLogger_SetLogLevel(logger, MetisLoggerFacility_IO, PARCLogLevel_Warning); + memset(_lastLogMessage, 0, _logLength); + + metisLogger_Log(logger, MetisLoggerFacility_IO, PARCLogLevel_Warning, __func__, "hello"); + assertTrue(strlen(_lastLogMessage) > 0, "Did not write to log message"); + metisLogger_Release(&logger); +} + +LONGBOW_TEST_CASE(Global, metisLogger_Log_IsNotLoggable) +{ + PARCLogReporter *reporter = _testWriter_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + + metisLogger_SetLogLevel(logger, MetisLoggerFacility_IO, PARCLogLevel_Warning); + memset(_lastLogMessage, 0, _logLength); + + metisLogger_Log(logger, MetisLoggerFacility_IO, PARCLogLevel_Debug, __func__, "hello"); + assertTrue(strlen(_lastLogMessage) == 0, "Should not have written to log message"); + metisLogger_Release(&logger); +} + + +// ========================================================== + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metis_Logger); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} + diff --git a/metis/ccnx/forwarder/metis/core/test/test_metis_Message.c b/metis/ccnx/forwarder/metis/core/test/test_metis_Message.c new file mode 100644 index 00000000..345a1440 --- /dev/null +++ b/metis/ccnx/forwarder/metis/core/test/test_metis_Message.c @@ -0,0 +1,946 @@ +/* + * 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 "../metis_Message.c" +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> +#include <parc/logging/parc_LogReporterTextStdout.h> + +#include <parc/logging/parc_LogReporterTextStdout.h> +#include <ccnx/forwarder/metis/testdata/metis_TestDataV0.h> +#include <ccnx/forwarder/metis/testdata/metis_TestDataV1.h> + +LONGBOW_TEST_RUNNER(metis_Message) +{ + // 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(metis_Message) +{ + 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(metis_Message) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, metisMessage_Create_InterestV0); + LONGBOW_RUN_TEST_CASE(Global, metisMessage_Create_ObjectV0); + + LONGBOW_RUN_TEST_CASE(Global, metisMessage_Create_InterestV1); + LONGBOW_RUN_TEST_CASE(Global, metisMessage_Create_ObjectV1); + + LONGBOW_RUN_TEST_CASE(Global, metisMessage_CreateFromBuffer); + LONGBOW_RUN_TEST_CASE(Global, metisMessage_CreateFromArray); + LONGBOW_RUN_TEST_CASE(Global, metisMessage_CreateFromElasticBuffer); + LONGBOW_RUN_TEST_CASE(Global, metisMessage_CreateFromBuffer_BadMessage); + LONGBOW_RUN_TEST_CASE(Global, metisMessage_CreateFromArray_BadMessage); + + LONGBOW_RUN_TEST_CASE(Global, metisMessage_Length); + LONGBOW_RUN_TEST_CASE(Global, metisMessage_Append); + LONGBOW_RUN_TEST_CASE(Global, metisMessage_Write); + LONGBOW_RUN_TEST_CASE(Global, metisMessage_GetConnectionId); + LONGBOW_RUN_TEST_CASE(Global, metisMessage_GetReceiveTime); + LONGBOW_RUN_TEST_CASE(Global, metisMessage_ReadFromBuffer); + LONGBOW_RUN_TEST_CASE(Global, metisMessage_Copy); + LONGBOW_RUN_TEST_CASE(Global, metisMessage_GetMessageType); + + LONGBOW_RUN_TEST_CASE(Global, metisMessage_GetName); + LONGBOW_RUN_TEST_CASE(Global, metisMessage_HasName_True); + LONGBOW_RUN_TEST_CASE(Global, metisMessage_HasName_False); + + LONGBOW_RUN_TEST_CASE(Global, metisMessage_GetKeyIdHash); + LONGBOW_RUN_TEST_CASE(Global, metisMessage_HasKeyId_True); + LONGBOW_RUN_TEST_CASE(Global, metisMessage_HasKeyId_False); + + LONGBOW_RUN_TEST_CASE(Global, metisMessage_KeyIdEquals_IsEqual); + LONGBOW_RUN_TEST_CASE(Global, metisMessage_KeyIdEquals_DifferentLength); + LONGBOW_RUN_TEST_CASE(Global, metisMessage_KeyIdEquals_DifferentValue); + + LONGBOW_RUN_TEST_CASE(Global, metisMessage_ObjectHashEquals_IsEqual_Precomputed); + LONGBOW_RUN_TEST_CASE(Global, metisMessage_ObjectHashEquals_IsEqual_Lazy); + LONGBOW_RUN_TEST_CASE(Global, metisMessage_ObjectHashEquals_IsNotEqual); + + LONGBOW_RUN_TEST_CASE(Global, metisMessage_ObjectHashHashCode_Precomputed); + LONGBOW_RUN_TEST_CASE(Global, metisMessage_ObjectHashHashCode_Lazy); + + LONGBOW_RUN_TEST_CASE(Global, metisMessage_HasContentObjectHash_True); + LONGBOW_RUN_TEST_CASE(Global, metisMessage_HasContentObjectHash_False); + + LONGBOW_RUN_TEST_CASE(Global, metisMessage_HasHopLimit_True); + LONGBOW_RUN_TEST_CASE(Global, metisMessage_HasHopLimit_False); + LONGBOW_RUN_TEST_CASE(Global, metisMessage_GetHopLimit); + LONGBOW_RUN_TEST_CASE(Global, metisMessage_SetHopLimit); + + LONGBOW_RUN_TEST_CASE(Global, metisMessage_HasInterestLifetime); + LONGBOW_RUN_TEST_CASE(Global, metisMessage_GetInterestLifetimeTicks); + + LONGBOW_RUN_TEST_CASE(Global, metisMessage_HasExpirationTime); + LONGBOW_RUN_TEST_CASE(Global, metisMessage_HasRecommendedCacheTime); + + LONGBOW_RUN_TEST_CASE(Global, metisMessage_SetGetExpirationTime); + LONGBOW_RUN_TEST_CASE(Global, metisMessage_SetGetRecommendedCacheTime); + + LONGBOW_RUN_TEST_CASE(Global, metisMessage_HasGetPublicKey); + LONGBOW_RUN_TEST_CASE(Global, metisMessage_IsPublicKeyVerified_True); + LONGBOW_RUN_TEST_CASE(Global, metisMessage_IsPublicKeyVerified_False); + + LONGBOW_RUN_TEST_CASE(Global, metisMessage_HasGetCertificate); +} + +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, metisMessage_Create_InterestV0) +{ + PARCEventBuffer *buff = parcEventBuffer_Create(); + parcEventBuffer_Append(buff, metisTestDataV0_EncodedInterest, sizeof(metisTestDataV0_EncodedInterest)); + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *message = metisMessage_CreateFromBuffer(1, 2, buff, logger); + metisLogger_Release(&logger); + + assertNotNull(message, "Got null from metisMessage_CreateFromBuffer"); + assertTrue(message->ingressConnectionId == 1, "IngressConnectionId wrong, expected %d got %u", 1, message->ingressConnectionId); + assertTrue(message->receiveTime == 2, "receiveTime wrong, expected %u got %" PRIu64, 2, message->receiveTime); + + metisMessage_Release(&message); +} + +LONGBOW_TEST_CASE(Global, metisMessage_Create_ObjectV0) +{ + PARCEventBuffer *buff = parcEventBuffer_Create(); + parcEventBuffer_Append(buff, metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject)); + + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *message = metisMessage_CreateFromBuffer(1, 2, buff, logger); + metisLogger_Release(&logger); + + assertNotNull(message, "Got null from metisMessage_CreateFromBuffer"); + assertTrue(message->ingressConnectionId == 1, "IngressConnectionId wrong, expected %d got %u", 1, message->ingressConnectionId); + assertTrue(message->receiveTime == 2, "receiveTime wrong, expected %u got %" PRIu64, 2, message->receiveTime); + + metisMessage_Release(&message); +} + +LONGBOW_TEST_CASE(Global, metisMessage_Create_InterestV1) +{ + PARCEventBuffer *buff = parcEventBuffer_Create(); + parcEventBuffer_Append(buff, metisTestDataV1_Interest_AllFields, sizeof(metisTestDataV1_Interest_AllFields)); + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *message = metisMessage_CreateFromBuffer(1, 2, buff, logger); + metisLogger_Release(&logger); + + assertNotNull(message, "Got null from metisMessage_CreateFromBuffer"); + assertTrue(message->ingressConnectionId == 1, "IngressConnectionId wrong, expected %d got %u", 1, message->ingressConnectionId); + assertTrue(message->receiveTime == 2, "receiveTime wrong, expected %u got %" PRIu64, 2, message->receiveTime); + + metisMessage_Release(&message); +} + +LONGBOW_TEST_CASE(Global, metisMessage_Create_ObjectV1) +{ + PARCEventBuffer *buff = parcEventBuffer_Create(); + parcEventBuffer_Append(buff, metisTestDataV1_ContentObject_NameA_Crc32c, sizeof(metisTestDataV1_ContentObject_NameA_Crc32c)); + + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *message = metisMessage_CreateFromBuffer(1, 2, buff, logger); + metisLogger_Release(&logger); + + assertNotNull(message, "Got null from metisMessage_CreateFromBuffer"); + assertTrue(message->ingressConnectionId == 1, "IngressConnectionId wrong, expected %d got %u", 1, message->ingressConnectionId); + assertTrue(message->receiveTime == 2, "receiveTime wrong, expected %u got %" PRIu64, 2, message->receiveTime); + + metisMessage_Release(&message); +} + + +LONGBOW_TEST_CASE(Global, metisMessage_CreateFromArray) +{ + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *message = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 2, logger); + metisLogger_Release(&logger); + + + assertNotNull(message, "Got null from metisMessage_CreateFromArray"); + assertTrue(message->ingressConnectionId == 1, "IngressConnectionId wrong, expected %d got %u", 1, message->ingressConnectionId); + assertTrue(message->receiveTime == 2, "receiveTime wrong, expected %u got %" PRIu64, 2, message->receiveTime); + + metisMessage_Release(&message); +} + +LONGBOW_TEST_CASE(Global, metisMessage_CreateFromArray_BadMessage) +{ + // Invalid version + char message_str[] = "\xFFOnce upon a time, in a stack far away, a dangling pointer found its way to the top of the heap."; + printf("metisMessage_CreateFromArray_BadMessage attempting to process a bad message which should report an error:\n"); + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *message = metisMessage_CreateFromArray((uint8_t *) message_str, sizeof(message_str), 1, 2, logger); + metisLogger_Release(&logger); + + assertNull(message, "Got null from metisMessage_CreateFromArray"); +} + +LONGBOW_TEST_CASE(Global, metisMessage_CreateFromBuffer) +{ + char message_str[] = "\x00Once upon a time, in a stack far away, a dangling pointer found its way to the top of the heap."; + + PARCEventBuffer *buff = parcEventBuffer_Create(); + parcEventBuffer_Append(buff, message_str, sizeof(message_str)); + + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *message = metisMessage_CreateFromBuffer(1, 2, buff, logger); + metisLogger_Release(&logger); + + assertNotNull(message, "Got null from metisMessage_CreateFromBuffer"); + assertTrue(message->ingressConnectionId == 1, "IngressConnectionId wrong, expected %d got %u", 1, message->ingressConnectionId); + assertTrue(message->receiveTime == 2, "receiveTime wrong, expected %u got %" PRIu64, 2, message->receiveTime); + + metisMessage_Release(&message); +} + +LONGBOW_TEST_CASE(Global, metisMessage_CreateFromElasticBuffer) +{ + char message_str[] = "\0x00Once upon a time, in a stack far away, a dangling pointer found its way to the top of the heap."; + + PARCBuffer *buff = parcBuffer_Wrap(message_str, sizeof(message_str), 0, sizeof(message_str)); + + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *message = metisMessage_CreateFromParcBuffer(buff, 1, 2, logger); + metisLogger_Release(&logger); + + assertNotNull(message, "Got null from metisMessage_CreateFromBuffer"); + assertTrue(message->ingressConnectionId == 1, "IngressConnectionId wrong, expected %d got %u", 1, message->ingressConnectionId); + assertTrue(message->receiveTime == 2, "receiveTime wrong, expected %u got %" PRIu64, 2, message->receiveTime); + + metisMessage_Release(&message); + parcBuffer_Release(&buff); +} + +LONGBOW_TEST_CASE(Global, metisMessage_CreateFromBuffer_BadMessage) +{ + // Bad version + char message_str[] = "\xFFOnce upon a time, in a stack far away, a dangling pointer found its way to the top of the heap."; + + printf("metisMessage_CreateFromBuffer_BadMessage attempting to process a bad message which should report an error:\n"); + PARCEventBuffer *buff = parcEventBuffer_Create(); + parcEventBuffer_Append(buff, message_str, sizeof(message_str)); + + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *message = metisMessage_CreateFromBuffer(1, 2, buff, logger); + metisLogger_Release(&logger); + + assertNull(message, "Got null from metisMessage_CreateFromBuffer"); +} + +LONGBOW_TEST_CASE(Global, metisMessage_ReadFromBuffer) +{ + char message_str[] = "\x00Once upon a time, in a stack far away, a dangling pointer found its way to the top of the heap."; + + PARCEventBuffer *buff = parcEventBuffer_Create(); + parcEventBuffer_Append(buff, message_str, sizeof(message_str)); + + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *message = metisMessage_ReadFromBuffer(1, 2, buff, sizeof(message_str), logger); + metisLogger_Release(&logger); + + assertNotNull(message, "Got null from metisMessage_CreateFromBuffer"); + + assertTrue(parcEventBuffer_GetLength(message->messageBytes) == sizeof(message_str), + "Length of internal buffer wrong, expected %zu got %zu", + sizeof(message_str), + parcEventBuffer_GetLength(message->messageBytes)); + + uint8_t *p = parcEventBuffer_Pullup(message->messageBytes, sizeof(message_str)); + assertTrue(memcmp(p, message_str, sizeof(message_str)) == 0, "Internal buffer contents does not match test"); + assertTrue(message->ingressConnectionId == 1, "IngressConnectionId wrong, expected %d got %u", 1, message->ingressConnectionId); + assertTrue(message->receiveTime == 2, "receiveTime wrong, expected %u got %" PRIu64, 2, message->receiveTime); + assertTrue(parcEventBuffer_GetLength(buff) == 0, "Origin buffer not drained, expected 0, got %zu", parcEventBuffer_GetLength(buff)); + + metisMessage_Release(&message); + parcEventBuffer_Destroy(&buff); +} + +LONGBOW_TEST_CASE(Global, metisMessage_Append) +{ + char message_str[] = "\x00Once upon a time ..."; + + PARCEventBuffer *buffer = parcEventBuffer_Create(); + PARCEventBuffer *buff = parcEventBuffer_Create(); + parcEventBuffer_Append(buff, message_str, sizeof(message_str)); + + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *message = metisMessage_CreateFromBuffer(1, 2, buff, logger); + int result = metisMessage_Append(buffer, message); + + assertTrue(result == 0, "Got error from metisMessage_Append"); + metisLogger_Release(&logger); + metisMessage_Release(&message); + parcEventBuffer_Destroy(&buffer); +} + +LONGBOW_TEST_CASE(Global, metisMessage_Write) +{ + char message_str[] = "\x00Once upon a time ..."; + + PARCEventScheduler *scheduler = parcEventScheduler_Create(); + PARCEventQueue *queue = parcEventQueue_Create(scheduler, -1, PARCEventQueueOption_CloseOnFree); + + PARCEventBuffer *buff = parcEventBuffer_Create(); + parcEventBuffer_Append(buff, message_str, sizeof(message_str)); + + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *message = metisMessage_CreateFromBuffer(1, 2, buff, logger); + int result = metisMessage_Write(queue, message); + + assertTrue(result == 0, "Got error from metisMessage_Write"); + + // buff is deallocated by metisMessage_Release + metisLogger_Release(&logger); + metisMessage_Release(&message); + parcEventQueue_Destroy(&queue); + parcEventScheduler_Destroy(&scheduler); +} + +LONGBOW_TEST_CASE(Global, metisMessage_Length) +{ + char message_str[] = "\x00Once upon a time, in a stack far away, a dangling pointer found its way to the top of the heap."; + + PARCEventBuffer *buff = parcEventBuffer_Create(); + parcEventBuffer_Append(buff, message_str, sizeof(message_str)); + + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *message = metisMessage_CreateFromBuffer(1, 2, buff, logger); + metisLogger_Release(&logger); + + assertNotNull(message, "Got null from metisMessage_CreateFromBuffer"); + size_t length = metisMessage_Length(message); + assertTrue(length == sizeof(message_str), "Wrong length, expected %zu got %zu", sizeof(message_str), length); + metisMessage_Release(&message); +} + +LONGBOW_TEST_CASE(Global, metisMessage_GetConnectionId) +{ + char message_str[] = "\x00Once upon a time, in a stack far away, a dangling pointer found its way to the top of the heap."; + + PARCEventBuffer *buff = parcEventBuffer_Create(); + parcEventBuffer_Append(buff, message_str, sizeof(message_str)); + + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *message = metisMessage_CreateFromBuffer(1, 2, buff, logger); + metisLogger_Release(&logger); + + assertNotNull(message, "Got null from metisMessage_CreateFromBuffer"); + unsigned connid = metisMessage_GetIngressConnectionId(message); + + assertTrue(connid == 1, "Wrong length, expected %u got %u", 1, connid); + metisMessage_Release(&message); +} + +LONGBOW_TEST_CASE(Global, metisMessage_GetReceiveTime) +{ + char message_str[] = "\x00Once upon a time, in a stack far away, a dangling pointer found its way to the top of the heap."; + + PARCEventBuffer *buff = parcEventBuffer_Create(); + parcEventBuffer_Append(buff, message_str, sizeof(message_str)); + + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *message = metisMessage_CreateFromBuffer(1, 2, buff, logger); + metisLogger_Release(&logger); + + assertNotNull(message, "Got null from metisMessage_CreateFromBuffer"); + MetisTicks time = metisMessage_GetReceiveTime(message); + + assertTrue(time == 2, "Wrong receive time, expected %u got %" PRIu64, 2, time); + metisMessage_Release(&message); +} + +LONGBOW_TEST_CASE(Global, metisMessage_Copy) +{ + char message_str[] = "\x00Once upon a time, in a stack far away, a dangling pointer found its way to the top of the heap."; + + PARCEventBuffer *buff = parcEventBuffer_Create(); + parcEventBuffer_Append(buff, message_str, sizeof(message_str)); + + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *message = metisMessage_CreateFromBuffer(1, 2, buff, logger); + metisLogger_Release(&logger); + + assertNotNull(message, "Got null from metisMessage_CreateFromBuffer"); + assertTrue(message->refcount == 1, "Incorrect refcount, expected %u got %u", 1, message->refcount); + + MetisMessage *copy = metisMessage_Acquire(message); + assertTrue(message->refcount == 2, "Incorrect refcount, expected %u got %u", 2, message->refcount); + + metisMessage_Release(&message); + assertTrue(copy->refcount == 1, "Incorrect refcount, expected %u got %u", 1, message->refcount); + + metisMessage_Release(©); + + assertTrue(parcMemory_Outstanding() == 0, "Memory balance should be zero after destroying last copy, got %u", parcMemory_Outstanding()); +} + +LONGBOW_TEST_CASE(Global, metisMessage_GetMessageType) +{ + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *message = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 2, logger); + metisLogger_Release(&logger); + MetisMessagePacketType type = metisMessage_GetType(message); + + assertTrue(type == MetisMessagePacketType_ContentObject, "wrong type, expected %u got %u", MetisMessagePacketType_ContentObject, type); + + metisMessage_Release(&message); +} + +LONGBOW_TEST_CASE(Global, metisMessage_GetName) +{ + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *message = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 2, logger); + metisLogger_Release(&logger); + MetisTlvName *name = metisMessage_GetName(message); + MetisTlvName *truth = metisTlvName_Create(&metisTestDataV0_EncodedObject[metisTestDataV0_EncodedObject_name.offset], metisTestDataV0_EncodedObject_name.length); + + assertTrue(metisTlvName_Equals(truth, name), "Did not get back the right name"); + + metisTlvName_Release(&truth); + metisMessage_Release(&message); +} + +LONGBOW_TEST_CASE(Global, metisMessage_HasName_True) +{ + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *message = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 2, logger); + metisLogger_Release(&logger); + bool hasName = metisMessage_HasName(message); + assertTrue(hasName, "Message with a name says it does not"); + metisMessage_Release(&message); +} + +LONGBOW_TEST_CASE(Global, metisMessage_HasName_False) +{ + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *message = metisMessage_CreateFromArray(metisTestDataV0_CPIMessage, sizeof(metisTestDataV0_CPIMessage), 1, 2, logger); + metisLogger_Release(&logger); + bool hasName = metisMessage_HasName(message); + assertFalse(hasName, "Message without a name says it does"); + metisMessage_Release(&message); +} + +LONGBOW_TEST_CASE(Global, metisMessage_HasContentObjectHash_True) +{ + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *message = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 2, logger); + metisLogger_Release(&logger); + bool hasHash = metisMessage_HasContentObjectHash(message); + assertTrue(hasHash, "Message with a content object hash says it does not"); + metisMessage_Release(&message); +} + +LONGBOW_TEST_CASE(Global, metisMessage_HasContentObjectHash_False) +{ + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *message = metisMessage_CreateFromArray(metisTestDataV0_EncodedInterest, sizeof(metisTestDataV0_EncodedInterest), 1, 2, logger); + metisLogger_Release(&logger); + bool hasHash = metisMessage_HasContentObjectHash(message); + assertTrue(hasHash, "Message without a content object hash says it does"); + metisMessage_Release(&message); +} + +LONGBOW_TEST_CASE(Global, metisMessage_GetKeyIdHash) +{ + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *message = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 2, logger); + metisLogger_Release(&logger); + + uint32_t truthhash = parcHash32_Data(&metisTestDataV0_EncodedObject[metisTestDataV0_EncodedObject_keyid.offset], metisTestDataV0_EncodedObject_keyid.length); + uint32_t testhash; + bool success = metisMessage_GetKeyIdHash(message, &testhash); + + assertTrue(success, "Failed metisMessage_GetKeyIdHash, returned false"); + assertTrue(truthhash == testhash, "Hash compared wrong, expected %08X, got %08X", truthhash, testhash); + + metisMessage_Release(&message); +} + +LONGBOW_TEST_CASE(Global, metisMessage_HasKeyId_True) +{ + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *message = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 2, logger); + metisLogger_Release(&logger); + bool hasKeyId = metisMessage_HasKeyId(message); + assertTrue(hasKeyId, "Message with a keyid says it does not"); + metisMessage_Release(&message); +} + +LONGBOW_TEST_CASE(Global, metisMessage_HasKeyId_False) +{ + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *message = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 2, logger); + metisLogger_Release(&logger); + bool hasKeyId = metisMessage_HasKeyId(message); + assertFalse(hasKeyId, "Message without a keyid says it does"); + metisMessage_Release(&message); +} + +LONGBOW_TEST_CASE(Global, metisMessage_KeyIdEquals_IsEqual) +{ + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *a = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 2, logger); + MetisMessage *b = metisMessage_CreateFromArray(metisTestDataV0_EncodedInterest, sizeof(metisTestDataV0_EncodedInterest), 1, 2, logger); + metisLogger_Release(&logger); + + assertTrue(metisMessage_KeyIdEquals(a, b), "Messages with equal keyids did not compare"); + metisMessage_Release(&a); + metisMessage_Release(&b); +} + +LONGBOW_TEST_CASE(Global, metisMessage_KeyIdEquals_DifferentLength) +{ + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *a = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 2, logger); + MetisMessage *b = metisMessage_CreateFromArray(metisTestDataV0_SecondObject, sizeof(metisTestDataV0_SecondObject), 1, 2, logger); + metisLogger_Release(&logger); + + assertFalse(metisMessage_KeyIdEquals(a, b), "Messages with differnt length keyids did compared equal"); + metisMessage_Release(&a); + metisMessage_Release(&b); +} + +LONGBOW_TEST_CASE(Global, metisMessage_KeyIdEquals_DifferentValue) +{ + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *a = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 2, logger); + MetisMessage *b = metisMessage_CreateFromArray(metisTestDataV0_SecondInterest, sizeof(metisTestDataV0_SecondInterest), 1, 2, logger); + metisLogger_Release(&logger); + + assertFalse(metisMessage_KeyIdEquals(a, b), "Messages with differnt keyids did compared equal"); + metisMessage_Release(&a); + metisMessage_Release(&b); +} + +LONGBOW_TEST_CASE(Global, metisMessage_ObjectHashEquals_IsEqual_Precomputed) +{ + // create messages from Interests, as those are precomputed + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *a = metisMessage_CreateFromArray(metisTestDataV0_EncodedInterest, sizeof(metisTestDataV0_EncodedInterest), 1, 2, logger); + MetisMessage *b = metisMessage_CreateFromArray(metisTestDataV0_EncodedInterest, sizeof(metisTestDataV0_EncodedInterest), 1, 2, logger); + metisLogger_Release(&logger); + + assertTrue(metisMessage_ObjectHashEquals(a, b), "Messages with equal ContentObjectHash did not compare"); + metisMessage_Release(&a); + metisMessage_Release(&b); +} + +LONGBOW_TEST_CASE(Global, metisMessage_ObjectHashEquals_IsEqual_Lazy) +{ + // create messages from content objects, as those are lazy computed + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *a = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 2, logger); + MetisMessage *b = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 2, logger); + metisLogger_Release(&logger); + + assertTrue(metisMessage_ObjectHashEquals(a, b), "Messages with equal ContentObjectHash did not compare"); + metisMessage_Release(&a); + metisMessage_Release(&b); +} + +LONGBOW_TEST_CASE(Global, metisMessage_ObjectHashEquals_IsNotEqual) +{ + // create messages from different content objects + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *a = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 2, logger); + MetisMessage *b = metisMessage_CreateFromArray(metisTestDataV0_SecondObject, sizeof(metisTestDataV0_SecondObject), 1, 2, logger); + metisLogger_Release(&logger); + + assertFalse(metisMessage_ObjectHashEquals(a, b), "Messages with unequal ContentObjectHash compared as equal"); + metisMessage_Release(&a); + metisMessage_Release(&b); +} + +LONGBOW_TEST_CASE(Global, metisMessage_ObjectHashHashCode_Precomputed) +{ + // create messages from Interests, as those are precomputed + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *a = metisMessage_CreateFromArray(metisTestDataV0_EncodedInterest, sizeof(metisTestDataV0_EncodedInterest), 1, 2, logger); + metisLogger_Release(&logger); + + uint32_t hashcode; + bool success = metisMessage_GetContentObjectHashHash(a, &hashcode); + assertTrue(success, "Returned false trying to get hash of contentobject hash"); + + metisMessage_Release(&a); +} + +LONGBOW_TEST_CASE(Global, metisMessage_ObjectHashHashCode_Lazy) +{ + // create messages from content object, as those are precomputed + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *a = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 2, logger); + metisLogger_Release(&logger); + + uint32_t hashcode; + bool success = metisMessage_GetContentObjectHashHash(a, &hashcode); + assertTrue(success, "Returned false trying to get hash of contentobject hash"); + + metisMessage_Release(&a); +} + +LONGBOW_TEST_CASE(Global, metisMessage_HasHopLimit_True) +{ + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *message = metisMessage_CreateFromArray(metisTestDataV0_EncodedInterest, sizeof(metisTestDataV0_EncodedInterest), 1, 2, logger); + metisLogger_Release(&logger); + + bool hasHopLimit = metisMessage_HasHopLimit(message); + assertTrue(hasHopLimit, "Message with a hop limit says it does not."); + + metisMessage_Release(&message); +} + +LONGBOW_TEST_CASE(Global, metisMessage_HasHopLimit_False) +{ + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *message = metisMessage_CreateFromArray(metisTestDataV0_EncodedInterest_no_hoplimit, sizeof(metisTestDataV0_EncodedInterest_no_hoplimit), 1, 2, logger); + metisLogger_Release(&logger); + + bool hasHopLimit = metisMessage_HasHopLimit(message); + assertFalse(hasHopLimit, "Message without a hop limit says it does."); + + metisMessage_Release(&message); +} + +LONGBOW_TEST_CASE(Global, metisMessage_GetHopLimit) +{ + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *message = metisMessage_CreateFromArray(metisTestDataV0_EncodedInterest, sizeof(metisTestDataV0_EncodedInterest), 1, 2, logger); + metisLogger_Release(&logger); + + uint8_t hoplimit = metisMessage_GetHopLimit(message); + assertTrue(hoplimit == 32, "Wrong hop limit, got %u expected %u.", hoplimit, 32); + + metisMessage_Release(&message); +} + +LONGBOW_TEST_CASE(Global, metisMessage_SetHopLimit) +{ + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *message = metisMessage_CreateFromArray(metisTestDataV0_EncodedInterest, sizeof(metisTestDataV0_EncodedInterest), 1, 2, logger); + metisLogger_Release(&logger); + + metisMessage_SetHopLimit(message, 99); + uint8_t hoplimit = metisMessage_GetHopLimit(message); + assertTrue(hoplimit == 99, "Wrong hop limit, got %u expected %u.", hoplimit, 99); + + metisMessage_Release(&message); +} + +LONGBOW_TEST_CASE(Global, metisMessage_HasInterestLifetime) +{ + PARCEventBuffer *buff = parcEventBuffer_Create(); + parcEventBuffer_Append(buff, metisTestDataV1_Interest_AllFields, sizeof(metisTestDataV1_Interest_AllFields)); + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *message = metisMessage_CreateFromBuffer(1, 2, buff, logger); + metisLogger_Release(&logger); + + assertTrue(metisMessage_HasInterestLifetime(message), "Should have returned true for interest lifetime"); + + metisMessage_Release(&message); +} + +LONGBOW_TEST_CASE(Global, metisMessage_GetInterestLifetimeTicks) +{ + PARCEventBuffer *buff = parcEventBuffer_Create(); + parcEventBuffer_Append(buff, metisTestDataV1_Interest_AllFields, sizeof(metisTestDataV1_Interest_AllFields)); + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *message = metisMessage_CreateFromBuffer(1, 2, buff, logger); + metisLogger_Release(&logger); + + // don't check actual value. It will vary based on METISHZ and rouding errors due to integer math + MetisTicks ticks = metisMessage_GetInterestLifetimeTicks(message); + assertTrue(ticks > 0, "Should have gotten positive value for interest lifetime ticks"); + + metisMessage_Release(&message); +} + +LONGBOW_TEST_CASE(Global, metisMessage_HasExpirationTime) +{ + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + + // Note: Assumes metisTestDataV0_EncodedObject doesn't have ExpiryTime. + MetisMessage *message = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 2, logger); + metisLogger_Release(&logger); + + bool hasExpiryTime = metisMessage_HasExpiryTime(message); + assertFalse(hasExpiryTime, "Message without ExpiryTime says it has one."); + + metisMessage_SetExpiryTimeTicks(message, 10000); + hasExpiryTime = metisMessage_HasExpiryTime(message); + assertTrue(hasExpiryTime, "Message with ExpiryTime says it doesn't have one."); + + metisMessage_Release(&message); +} + +LONGBOW_TEST_CASE(Global, metisMessage_HasRecommendedCacheTime) +{ + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + + // Note: Assumes metisTestDataV0_EncodedObject doesn't have RCT. + MetisMessage *message = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 2, logger); + metisLogger_Release(&logger); + + bool hasRCT = metisMessage_HasRecommendedCacheTime(message); + assertFalse(hasRCT, "Message without hasRCT says it has one."); + + metisMessage_SetRecommendedCacheTimeTicks(message, 10000); + hasRCT = metisMessage_HasRecommendedCacheTime(message); + assertTrue(hasRCT, "Message with hasRCT says it doesn't have one."); + + metisMessage_Release(&message); +} + +LONGBOW_TEST_CASE(Global, metisMessage_SetGetExpirationTime) +{ + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + + // Note: Assumes metisTestDataV0_EncodedObject doesn't have RCT. + MetisMessage *message = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 2, logger); + metisLogger_Release(&logger); + + uint64_t time = 12345; + metisMessage_SetExpiryTimeTicks(message, time); + assertTrue(time == metisMessage_GetExpiryTimeTicks(message), "Retrieved unexpected ExpiryTime"); + + metisMessage_Release(&message); +} + +LONGBOW_TEST_CASE(Global, metisMessage_SetGetRecommendedCacheTime) +{ + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + + // Note: Assumes metisTestDataV0_EncodedObject doesn't have RCT. + MetisMessage *message = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 2, logger); + metisLogger_Release(&logger); + + uint64_t time = 12345; + metisMessage_SetRecommendedCacheTimeTicks(message, time); + assertTrue(time == metisMessage_GetRecommendedCacheTimeTicks(message), "Retrieved unexpected RCT"); + + metisMessage_Release(&message); +} + +LONGBOW_TEST_CASE(Global, metisMessage_HasGetPublicKey) +{ + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + + MetisMessage *contentWithKey = + metisMessage_CreateFromArray(metisTestDataV1_ContentObject_NameA_KeyId1_RsaSha256, + sizeof(metisTestDataV1_ContentObject_NameA_KeyId1_RsaSha256), 1, 2, logger); + + MetisMessage *interestWithKeyIdRestriction = + metisMessage_CreateFromArray(metisTestDataV1_Interest_NameAAndKeyId, + sizeof(metisTestDataV1_Interest_NameAAndKeyId), 1, 2, logger); + + metisLogger_Release(&logger); + + assertTrue(metisMessage_HasPublicKey(contentWithKey), "Expected to see a public key"); + assertFalse(metisMessage_HasPublicKey(interestWithKeyIdRestriction), "Expected to not see a public key"); + + PARCBuffer *key = metisMessage_GetPublicKey(contentWithKey); + + assertNotNull(key, "Expected to retrieve the public key"); + + metisMessage_Release(&contentWithKey); + metisMessage_Release(&interestWithKeyIdRestriction); +} + +LONGBOW_TEST_CASE(Global, metisMessage_IsPublicKeyVerified_False) +{ + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + + MetisMessage *contentWithKey = + metisMessage_CreateFromArray(metisTestDataV1_ContentObject_NameA_KeyId1_RsaSha256, + sizeof(metisTestDataV1_ContentObject_NameA_KeyId1_RsaSha256), 1, 2, logger); + + MetisMessage *interestWithKeyIdRestriction = + metisMessage_CreateFromArray(metisTestDataV1_Interest_NameAAndKeyId, + sizeof(metisTestDataV1_Interest_NameAAndKeyId), 1, 2, logger); + + metisLogger_Release(&logger); + + assertFalse(metisMessage_IsKeyIdVerified(contentWithKey), "Expected key to not be verified."); + + // This is an interest. The keyId is actually a KeyId restriction, so will never be verified. + assertFalse(metisMessage_IsKeyIdVerified(interestWithKeyIdRestriction), "Expected key to not be verified."); + + PARCBuffer *key = metisMessage_GetPublicKey(contentWithKey); + + assertNotNull(key, "Expected to retrieve the public key"); + + metisMessage_Release(&contentWithKey); + metisMessage_Release(&interestWithKeyIdRestriction); +} + +LONGBOW_TEST_CASE(Global, metisMessage_IsPublicKeyVerified_True) +{ + testUnimplemented("Verification of KeyIds in ContentObjects is not yet implemented."); +} + +LONGBOW_TEST_CASE(Global, metisMessage_HasGetCertificate) +{ + testUnimplemented("Need test data with an encoded certificate."); +} + +// =================================================== + +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(metis_Message); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/metis/ccnx/forwarder/metis/core/test/test_metis_NumberSet.c b/metis/ccnx/forwarder/metis/core/test/test_metis_NumberSet.c new file mode 100644 index 00000000..461e5e62 --- /dev/null +++ b/metis/ccnx/forwarder/metis/core/test/test_metis_NumberSet.c @@ -0,0 +1,557 @@ +/* + * 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 "../metis_NumberSet.c" +#include <LongBow/unit-test.h> + +#include <parc/algol/parc_SafeMemory.h> + +LONGBOW_TEST_RUNNER(metis_NumberSet) +{ + // 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(metis_NumberSet) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(metis_NumberSet) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, metisNumberSet_Append_NoExpand); + LONGBOW_RUN_TEST_CASE(Global, metisNumberSet_Append_Expand); + LONGBOW_RUN_TEST_CASE(Global, metisNumberSet_Append_Duplicate); + LONGBOW_RUN_TEST_CASE(Global, metisNumberSet_Contains); + LONGBOW_RUN_TEST_CASE(Global, metisNumberSet_Copy); + LONGBOW_RUN_TEST_CASE(Global, metisNumberSet_Create_Destroy); + + LONGBOW_RUN_TEST_CASE(Global, metisNumberSet_Equals_IsEqual); + LONGBOW_RUN_TEST_CASE(Global, metisNumberSet_Equals_BothEmpty); + LONGBOW_RUN_TEST_CASE(Global, metisNumberSet_Equals_BothNull); + LONGBOW_RUN_TEST_CASE(Global, metisNumberSet_Equals_OneNull); + LONGBOW_RUN_TEST_CASE(Global, metisNumberSet_Equals_DifferentLengths); + LONGBOW_RUN_TEST_CASE(Global, metisNumberSet_Equals_IsNotEqual); + + LONGBOW_RUN_TEST_CASE(Global, metisNumberSet_GetItem); + LONGBOW_RUN_TEST_CASE(Global, metisNumberSet_Length); + LONGBOW_RUN_TEST_CASE(Global, metisNumberSet_Subtract_Disjoint); + LONGBOW_RUN_TEST_CASE(Global, metisNumberSet_Subtract_Equivalent); + LONGBOW_RUN_TEST_CASE(Global, metisNumberSet_Subtract_Overlap); + + LONGBOW_RUN_TEST_CASE(Global, metisNumberSet_Remove_LastElement); + LONGBOW_RUN_TEST_CASE(Global, metisNumberSet_Remove_AllElements); + LONGBOW_RUN_TEST_CASE(Global, metisNumberSet_Remove_FirstElement); +} + +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, metisNumberSet_Append_NoExpand) +{ + MetisNumberSet *set = metisNumberSet_Create(); + + for (int i = 1; i <= set->limit; i++) { + bool result = metisNumberSet_Add(set, i); + assertTrue(result, "Got failure on append, i = %d", i); + assertTrue(set->length == i, "Set length wrong, expected %d got %zu", i, set->length); + } + + metisNumberSet_Release(&set); +} + +LONGBOW_TEST_CASE(Global, metisNumberSet_Append_Expand) +{ + MetisNumberSet *set = metisNumberSet_Create(); + + size_t limit = set->limit; + for (int i = 1; i <= limit + 5; i++) { + bool result = metisNumberSet_Add(set, i); + assertTrue(result, "Got failure on append, i = %d", i); + assertTrue(set->length == i, "Set length wrong, expected %d got %zu", i, set->length); + } + + metisNumberSet_Release(&set); +} + +LONGBOW_TEST_CASE(Global, metisNumberSet_Append_Duplicate) +{ + MetisNumberSet *set = metisNumberSet_Create(); + + for (int i = 1; i <= set->limit; i++) { + bool result = metisNumberSet_Add(set, i); + assertTrue(result, "Got failure on append, i = %d", i); + assertTrue(set->length == i, "Set length wrong, expected %d got %zu", i, set->length); + } + + for (int i = 1; i <= set->limit; i++) { + bool result = metisNumberSet_Add(set, i); + assertFalse(result, "Got success on duplicate append, i = %d", i); + assertTrue(set->length == set->limit, "Set length wrong, expected %zu got %zu", set->limit, set->length); + } + + metisNumberSet_Release(&set); +} + +LONGBOW_TEST_CASE(Global, metisNumberSet_Contains) +{ + MetisNumberSet *set = metisNumberSet_Create(); + + int limit = 10; + for (int i = 1; i <= limit; i++) { + bool result = metisNumberSet_Add(set, i); + assertTrue(result, "Got failure on append, i = %d", i); + assertTrue(set->length == i, "Set length wrong, expected %d got %zu", i, set->length); + } + + for (int i = 1; i <= limit; i++) { + bool result = metisNumberSet_Contains(set, i); + assertTrue(result, "Got missing member, i = %d", i); + } + + for (int i = limit + 1; i <= 2 * limit; i++) { + bool result = metisNumberSet_Contains(set, i); + assertFalse(result, "Got contains returned true for missing element, i = %d", i); + } + + metisNumberSet_Release(&set); +} + +LONGBOW_TEST_CASE(Global, metisNumberSet_Copy) +{ + MetisNumberSet *set = metisNumberSet_Create(); + + int limit = 10; + for (int i = 1; i <= limit; i++) { + bool result = metisNumberSet_Add(set, i); + assertTrue(result, "Got failure on append, i = %d", i); + assertTrue(set->length == i, "Set length wrong, expected %d got %zu", i, set->length); + } + + MetisNumberSet *copy = metisNumberSet_Acquire(set); + assertTrue(set->refcount == 2, "Set refcount not 2: %u", set->refcount); + + metisNumberSet_Release(©); + assertTrue(set->refcount == 1, "Set refcount not 1: %u", set->refcount); + + metisNumberSet_Release(&set); +} + +LONGBOW_TEST_CASE(Global, metisNumberSet_Create_Destroy) +{ + MetisNumberSet *set = metisNumberSet_Create(); + assertTrue(set->length == 0, "Set not 0 length on create: %zu", set->length); + assertTrue(set->refcount == 1, "Set refcount not 1: %u", set->refcount); + metisNumberSet_Release(&set); + + assertTrue(parcSafeMemory_ReportAllocation(STDOUT_FILENO) == 0, "Memory imbalance on create/destroy: %u", parcMemory_Outstanding()); +} + +LONGBOW_TEST_CASE(Global, metisNumberSet_Equals_IsEqual) +{ + // 0 is the terminator + unsigned a_set[] = { 1, 2, 3, 4, 5, 6, 7, 0 }; + unsigned b_set[] = { 1, 2, 3, 4, 5, 6, 7, 0 }; + + MetisNumberSet *a = metisNumberSet_Create(); + MetisNumberSet *b = metisNumberSet_Create(); + + for (int i = 0; a_set[i] != 0; i++) { + metisNumberSet_Add(a, a_set[i]); + } + + for (int i = 0; b_set[i] != 0; i++) { + metisNumberSet_Add(b, b_set[i]); + } + + bool equal = metisNumberSet_Equals(a, b); + + metisNumberSet_Release(&a); + metisNumberSet_Release(&b); + + assertTrue(equal, "Equal sets did not compare as equal"); +} + +LONGBOW_TEST_CASE(Global, metisNumberSet_Equals_BothEmpty) +{ + MetisNumberSet *a = metisNumberSet_Create(); + MetisNumberSet *b = metisNumberSet_Create(); + + bool equal = metisNumberSet_Equals(a, b); + + metisNumberSet_Release(&a); + metisNumberSet_Release(&b); + + assertTrue(equal, "Two empty sets did not compare as equal"); +} + +LONGBOW_TEST_CASE(Global, metisNumberSet_Equals_BothNull) +{ + MetisNumberSet *a = NULL; + MetisNumberSet *b = NULL; + + bool equal = metisNumberSet_Equals(a, b); + + assertTrue(equal, "Two NULL sets did not compare as equal"); +} + +LONGBOW_TEST_CASE(Global, metisNumberSet_Equals_OneNull) +{ + MetisNumberSet *a = NULL; + MetisNumberSet *b = metisNumberSet_Create(); + + bool equal = metisNumberSet_Equals(a, b); + + assertFalse(equal, "One null one allocated sets did compared as equal"); + metisNumberSet_Release(&b); +} + +LONGBOW_TEST_CASE(Global, metisNumberSet_Equals_DifferentLengths) +{ + // 0 is the terminator + unsigned a_set[] = { 1, 2, 3, 4, 5, 6, 7, 0 }; + unsigned b_set[] = { 1, 2, 3, 4, 5, 6, 0 }; + + MetisNumberSet *a = metisNumberSet_Create(); + MetisNumberSet *b = metisNumberSet_Create(); + + for (int i = 0; a_set[i] != 0; i++) { + metisNumberSet_Add(a, a_set[i]); + } + + for (int i = 0; b_set[i] != 0; i++) { + metisNumberSet_Add(b, b_set[i]); + } + + bool equal = metisNumberSet_Equals(a, b); + + metisNumberSet_Release(&a); + metisNumberSet_Release(&b); + + assertFalse(equal, "Sets of different lengths compared as equal"); +} + +LONGBOW_TEST_CASE(Global, metisNumberSet_Equals_IsNotEqual) +{ + // 0 is the terminator + unsigned a_set[] = { 1, 2, 3, 4, 5, 6, 7, 0 }; + unsigned b_set[] = { 1, 2, 3, 4, 5, 6, 8, 0 }; + + MetisNumberSet *a = metisNumberSet_Create(); + MetisNumberSet *b = metisNumberSet_Create(); + + for (int i = 0; a_set[i] != 0; i++) { + metisNumberSet_Add(a, a_set[i]); + } + + for (int i = 0; b_set[i] != 0; i++) { + metisNumberSet_Add(b, b_set[i]); + } + + bool equal = metisNumberSet_Equals(a, b); + + metisNumberSet_Release(&a); + metisNumberSet_Release(&b); + + assertFalse(equal, "Same length but unequal sets compared as equal"); +} + +LONGBOW_TEST_CASE(Global, metisNumberSet_GetItem) +{ + MetisNumberSet *set = metisNumberSet_Create(); + + int limit = 10; + for (int i = 1; i <= limit; i++) { + bool result = metisNumberSet_Add(set, i); + assertTrue(result, "Got failure on append, i = %d", i); + assertTrue(set->length == i, "Set length wrong, expected %d got %zu", i, set->length); + } + + for (int i = 0; i < limit; i++) { + MetisNumber n = metisNumberSet_GetItem(set, i); + assertTrue(n == i + 1, "Got wrong number, i = %d, n = %u", i, n); + } + + metisNumberSet_Release(&set); +} + +LONGBOW_TEST_CASE(Global, metisNumberSet_Length) +{ + MetisNumberSet *set = metisNumberSet_Create(); + + int limit = 10; + for (int i = 1; i <= limit; i++) { + bool result = metisNumberSet_Add(set, i); + assertTrue(result, "Got failure on append, i = %d", i); + assertTrue(metisNumberSet_Length(set) == i, "Set length wrong, expected %d got %zu", i, metisNumberSet_Length(set)); + } + + metisNumberSet_Release(&set); +} + +LONGBOW_TEST_CASE(Global, metisNumberSet_Subtract_Disjoint) +{ + // 0 is the terminator + unsigned a_set[] = { 1, 2, 3, 4, 5, 6, 7, 0 }; + unsigned b_set[] = { 11, 12, 13, 14, 15, 0 }; + unsigned truth_set[] = { 1, 2, 3, 4, 5, 6, 7, 0 }; + + MetisNumberSet *a = metisNumberSet_Create(); + MetisNumberSet *b = metisNumberSet_Create(); + MetisNumberSet *truth = metisNumberSet_Create(); + + for (int i = 0; a_set[i] != 0; i++) { + metisNumberSet_Add(a, a_set[i]); + } + + for (int i = 0; b_set[i] != 0; i++) { + metisNumberSet_Add(b, b_set[i]); + } + + for (int i = 0; truth_set[i] != 0; i++) { + metisNumberSet_Add(truth, truth_set[i]); + } + + MetisNumberSet *test = metisNumberSet_Subtract(a, b); + + bool equal = metisNumberSet_Equals(truth, test); + + metisNumberSet_Release(&a); + metisNumberSet_Release(&b); + metisNumberSet_Release(&truth); + metisNumberSet_Release(&test); + + assertTrue(equal, "subtraction result incorrect for disjoint sets"); +} + +LONGBOW_TEST_CASE(Global, metisNumberSet_Subtract_Equivalent) +{ + // 0 is the terminator + unsigned a_set[] = { 1, 2, 3, 4, 5, 6, 7, 0 }; + unsigned b_set[] = { 1, 2, 3, 4, 5, 6, 7, 0 }; + unsigned truth_set[] = { 0 }; + + MetisNumberSet *a = metisNumberSet_Create(); + MetisNumberSet *b = metisNumberSet_Create(); + MetisNumberSet *truth = metisNumberSet_Create(); + + for (int i = 0; a_set[i] != 0; i++) { + metisNumberSet_Add(a, a_set[i]); + } + + for (int i = 0; b_set[i] != 0; i++) { + metisNumberSet_Add(b, b_set[i]); + } + + for (int i = 0; truth_set[i] != 0; i++) { + metisNumberSet_Add(truth, truth_set[i]); + } + + MetisNumberSet *test = metisNumberSet_Subtract(a, b); + + bool equal = metisNumberSet_Equals(truth, test); + + metisNumberSet_Release(&a); + metisNumberSet_Release(&b); + metisNumberSet_Release(&truth); + metisNumberSet_Release(&test); + + assertTrue(equal, "subtraction result incorrect for disjoint sets"); +} + +LONGBOW_TEST_CASE(Global, metisNumberSet_Subtract_Overlap) +{ + // 0 is the terminator + unsigned a_set[] = { 1, 2, 3, 4, 5, 6, 7, 0 }; + unsigned b_set[] = { 1, 2, 3, 4, 5, 0 }; + unsigned truth_set[] = { 6, 7, 0 }; + + MetisNumberSet *a = metisNumberSet_Create(); + MetisNumberSet *b = metisNumberSet_Create(); + MetisNumberSet *truth = metisNumberSet_Create(); + + for (int i = 0; a_set[i] != 0; i++) { + metisNumberSet_Add(a, a_set[i]); + } + + for (int i = 0; b_set[i] != 0; i++) { + metisNumberSet_Add(b, b_set[i]); + } + + for (int i = 0; truth_set[i] != 0; i++) { + metisNumberSet_Add(truth, truth_set[i]); + } + + MetisNumberSet *test = metisNumberSet_Subtract(a, b); + + bool equal = metisNumberSet_Equals(truth, test); + + metisNumberSet_Release(&a); + metisNumberSet_Release(&b); + metisNumberSet_Release(&truth); + metisNumberSet_Release(&test); + + assertTrue(equal, "subtraction result incorrect for disjoint sets"); +} + +LONGBOW_TEST_CASE(Global, metisNumberSet_Remove_LastElement) +{ + // 0 is the terminator + unsigned a_set[] = { 1, 2, 3, 4, 5, 6, 7, 0 }; + unsigned to_remove = 7; + unsigned truth_set[] = { 1, 2, 3, 4, 5, 6, 0 }; + + MetisNumberSet *a = metisNumberSet_Create(); + MetisNumberSet *truth = metisNumberSet_Create(); + + for (int i = 0; a_set[i] != 0; i++) { + metisNumberSet_Add(a, a_set[i]); + } + + for (int i = 0; truth_set[i] != 0; i++) { + metisNumberSet_Add(truth, truth_set[i]); + } + + metisNumberSet_Remove(a, to_remove); + + bool equal = metisNumberSet_Equals(truth, a); + + metisNumberSet_Release(&a); + metisNumberSet_Release(&truth); + + assertTrue(equal, "Removing element gives incorrect set"); +} + +LONGBOW_TEST_CASE(Global, metisNumberSet_Remove_AllElements) +{ + // 0 is the terminator + unsigned a_set[] = { 1, 0 }; + unsigned to_remove = 1; + unsigned truth_set[] = { 0 }; + + MetisNumberSet *a = metisNumberSet_Create(); + MetisNumberSet *truth = metisNumberSet_Create(); + + for (int i = 0; a_set[i] != 0; i++) { + metisNumberSet_Add(a, a_set[i]); + } + + for (int i = 0; truth_set[i] != 0; i++) { + metisNumberSet_Add(truth, truth_set[i]); + } + + metisNumberSet_Remove(a, to_remove); + + bool equal = metisNumberSet_Equals(truth, a); + + metisNumberSet_Release(&a); + metisNumberSet_Release(&truth); + + assertTrue(equal, "Removing element gives incorrect set"); +} + +LONGBOW_TEST_CASE(Global, metisNumberSet_Remove_FirstElement) +{ + // 0 is the terminator + unsigned a_set[] = { 1, 2, 3, 4, 5, 6, 7, 0 }; + unsigned to_remove = 1; + unsigned truth_set[] = { 2, 3, 4, 5, 6, 7, 0 }; + + MetisNumberSet *a = metisNumberSet_Create(); + MetisNumberSet *truth = metisNumberSet_Create(); + + for (int i = 0; a_set[i] != 0; i++) { + metisNumberSet_Add(a, a_set[i]); + } + + for (int i = 0; truth_set[i] != 0; i++) { + metisNumberSet_Add(truth, truth_set[i]); + } + + metisNumberSet_Remove(a, to_remove); + + bool equal = metisNumberSet_Equals(truth, a); + + metisNumberSet_Release(&a); + metisNumberSet_Release(&truth); + + assertTrue(equal, "Removing element gives incorrect set"); +} + +// ====================================================================================== + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, metisNumberSet_Expand); + LONGBOW_RUN_TEST_CASE(Local, metisNumberSet_AddNoChecks); +} + +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, metisNumberSet_Expand) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Local, metisNumberSet_AddNoChecks) +{ + testUnimplemented("This test is unimplemented"); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metis_NumberSet); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/metis/ccnx/forwarder/metis/core/test/test_metis_StreamBuffer.c b/metis/ccnx/forwarder/metis/core/test/test_metis_StreamBuffer.c new file mode 100644 index 00000000..09bd9401 --- /dev/null +++ b/metis/ccnx/forwarder/metis/core/test/test_metis_StreamBuffer.c @@ -0,0 +1,134 @@ +/* + * 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 "../metis_StreamBuffer.c" +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> + +LONGBOW_TEST_RUNNER(metis_StreamBuffer) +{ + // 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(metis_StreamBuffer) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(metis_StreamBuffer) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, metisStreamBuffer_Destroy); + LONGBOW_RUN_TEST_CASE(Global, metisStreamBuffer_DisableCallbacks); + LONGBOW_RUN_TEST_CASE(Global, metisStreamBuffer_EnableCallbacks); + LONGBOW_RUN_TEST_CASE(Global, metisStreamBuffer_Flush); + LONGBOW_RUN_TEST_CASE(Global, metisStreamBuffer_FlushCheckpoint); + LONGBOW_RUN_TEST_CASE(Global, metisStreamBuffer_FlushFinished); + LONGBOW_RUN_TEST_CASE(Global, metisStreamBuffer_SetCallbacks); + LONGBOW_RUN_TEST_CASE(Global, metisStreamBuffer_SetWatermark); +} + +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, metisStreamBuffer_Destroy) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, metisStreamBuffer_DisableCallbacks) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, metisStreamBuffer_EnableCallbacks) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, metisStreamBuffer_Flush) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, metisStreamBuffer_FlushCheckpoint) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, metisStreamBuffer_FlushFinished) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, metisStreamBuffer_SetCallbacks) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Global, metisStreamBuffer_SetWatermark) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_FIXTURE(Local) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) { + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metis_StreamBuffer); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/metis/ccnx/forwarder/metis/core/test/test_metis_ThreadedForwarder.c b/metis/ccnx/forwarder/metis/core/test/test_metis_ThreadedForwarder.c new file mode 100644 index 00000000..75579900 --- /dev/null +++ b/metis/ccnx/forwarder/metis/core/test/test_metis_ThreadedForwarder.c @@ -0,0 +1,145 @@ +/* + * 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 "../metis_ThreadedForwarder.c" + +#include <LongBow/unit-test.h> + +LONGBOW_TEST_RUNNER(metis_ThreadedForwarder) +{ + // 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(metis_ThreadedForwarder) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(metis_ThreadedForwarder) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, metisThreadedForwarder_AddCLI); + LONGBOW_RUN_TEST_CASE(Global, metisThreadedForwarder_Create); + LONGBOW_RUN_TEST_CASE(Global, metisThreadedForwarder_Destroy); + LONGBOW_RUN_TEST_CASE(Global, metisThreadedForwarder_SetupAllListeners); + LONGBOW_RUN_TEST_CASE(Global, metisThreadedForwarder_Start); + LONGBOW_RUN_TEST_CASE(Global, metisThreadedForwarder_Stop); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, metisThreadedForwarder_AddCLI) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_CASE(Global, metisThreadedForwarder_Create) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_CASE(Global, metisThreadedForwarder_Destroy) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_CASE(Global, metisThreadedForwarder_SetupAllListeners) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_CASE(Global, metisThreadedForwarder_Start) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_CASE(Global, metisThreadedForwarder_Stop) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, metisThreadedForwarder_BroadcastStatus); + LONGBOW_RUN_TEST_CASE(Local, metisThreadedForwarder_LockState); + LONGBOW_RUN_TEST_CASE(Local, metisThreadedForwarder_Run); + LONGBOW_RUN_TEST_CASE(Local, metisThreadedForwarder_UnlockState); + LONGBOW_RUN_TEST_CASE(Local, metisThreadedForwarder_WaitStatus); +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Local, metisThreadedForwarder_BroadcastStatus) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_CASE(Local, metisThreadedForwarder_LockState) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_CASE(Local, metisThreadedForwarder_Run) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_CASE(Local, metisThreadedForwarder_UnlockState) +{ + testUnimplemented(""); +} + +LONGBOW_TEST_CASE(Local, metisThreadedForwarder_WaitStatus) +{ + testUnimplemented(""); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metis_ThreadedForwarder); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/metis/ccnx/forwarder/metis/core/test/testrig_MetisIoOperations.h b/metis/ccnx/forwarder/metis/core/test/testrig_MetisIoOperations.h new file mode 100644 index 00000000..80735862 --- /dev/null +++ b/metis/ccnx/forwarder/metis/core/test/testrig_MetisIoOperations.h @@ -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. + */ + +#ifndef Metis_testrig_MetisIoOperations_h +#define Metis_testrig_MetisIoOperations_h + +/** + * Setup a test rig around a MetisIoOperation so we have visibility in to + * what the connection table is doing + * + * Usage: Use <code>mockIoOperationsData_Create()</code> or <code>mockIoOperationsData_CreateSimple()</code> + * to create the MetisIoOperations. You can then inspect the TestData inside the context + * by mapping <code>TestData *data = (TestData *) metisIoOperations_GetClosure(ops)</code>. + * + * IMPORTANT: ops->destroy(&ops) will not destroy the test rig. It will increment a counter. + * you must call <code>testdata_Destroy(&ops)</code> yourself. You should call this + * as the very last thing, even after <code>metisForwarder_Destroy()</code>, if you put + * the MetisIoOpereations in the connection table. + */ +static bool mockIoOperations_Send(MetisIoOperations *ops, const CPIAddress *nexthop, MetisMessage *message); +static const CPIAddress *mockIoOperations_GetRemoteAddress(const MetisIoOperations *ops); +static const MetisAddressPair *mockIoOperations_GetAddressPair(const MetisIoOperations *ops); +static bool mockIoOperations_IsUp(const MetisIoOperations *ops); +static bool mockIoOperations_IsLocal(const MetisIoOperations *ops); +static unsigned mockIoOperations_GetConnectionId(const MetisIoOperations *ops); +static void mockIoOperations_Destroy(MetisIoOperations **opsPtr); +static CPIConnectionType mockIoOperations_GetConnectionType(const MetisIoOperations *ops); +static const void *mockIoOperations_Class(const MetisIoOperations *ops); + +static MetisIoOperations mockIoOperationsTemplate = { + .closure = NULL, + .send = &mockIoOperations_Send, + .getRemoteAddress = &mockIoOperations_GetRemoteAddress, + .getAddressPair = &mockIoOperations_GetAddressPair, + .isUp = &mockIoOperations_IsUp, + .isLocal = &mockIoOperations_IsLocal, + .getConnectionId = &mockIoOperations_GetConnectionId, + .destroy = &mockIoOperations_Destroy, + .getConnectionType = &mockIoOperations_GetConnectionType, + .class = &mockIoOperations_Class +}; + +typedef struct mock_io_operations_data { + // counters for each call + unsigned sendCount; + unsigned getRemoteAddressCount; + unsigned getAddressPairCount; + unsigned isUpCount; + unsigned isLocalCount; + unsigned getConnectionIdCount; + unsigned destroyCount; + unsigned getConnectionTypeCount; + unsigned classCount; + + MetisMessage *lastMessage; + MetisAddressPair *addressPair; + unsigned id; + bool isUp; + bool isLocal; + bool sendResult; // what to return when send() called + CPIConnectionType connType; +} MockIoOperationsData; + +/** + * @function testdata_Create + * @abstract Creates a data set for testing MetisIoOperations + * @discussion + * Caller must explicitly use <code>testdata_Destroy()</code> when done. Calling the destroyer through + * the io operations only increments counters, it does not destroy the object. + * + * @param <#param1#> + * @return <#return#> + */ +static MetisIoOperations * +mockIoOperationsData_Create(MetisAddressPair *pair, unsigned id, bool isUp, bool sendResult, bool isLocal, CPIConnectionType connType) +{ + MockIoOperationsData *data = parcMemory_AllocateAndClear(sizeof(MockIoOperationsData)); + data->addressPair = pair; + data->id = id; + data->isUp = isUp; + data->sendResult = sendResult; + data->lastMessage = NULL; + data->isLocal = isLocal; + data->connType = connType; + + MetisIoOperations *ops = parcMemory_AllocateAndClear(sizeof(MetisIoOperations)); + memcpy(ops, &mockIoOperationsTemplate, sizeof(MetisIoOperations)); + ops->closure = data; + + return ops; +} + +/** + * @function testdata_CreateSimple + * @abstract Creates a data set for testing MetisIoOperations + * @discussion + * Caller must explicitly use <code>testdata_Destroy()</code> when done. Calling the destroyer through + * the io operations only increments counters, it does not destroy the object. + * + * @param <#param1#> + * @return <#return#> + */ +static MetisIoOperations * +mockIoOperationsData_CreateSimple(unsigned addressLocal, unsigned addressRemote, unsigned id, bool isUp, bool sendResult, bool isLocal) +{ + CPIAddress *local = cpiAddress_CreateFromInterface(addressLocal); + CPIAddress *remote = cpiAddress_CreateFromInterface(addressRemote); + MetisAddressPair *pair = metisAddressPair_Create(local, remote); + MetisIoOperations *ops = mockIoOperationsData_Create(pair, id, isUp, sendResult, isLocal, cpiConnection_UDP); + cpiAddress_Destroy(&local); + cpiAddress_Destroy(&remote); + return ops; +} + +static void +mockIoOperationsData_Destroy(MetisIoOperations **opsPtr) +{ + MetisIoOperations *ops = *opsPtr; + MockIoOperationsData *data = (MockIoOperationsData *) metisIoOperations_GetClosure(ops); + + metisAddressPair_Release(&data->addressPair); + if (data->lastMessage) { + metisMessage_Release(&data->lastMessage); + } + parcMemory_Deallocate((void **) &data); + ops->closure = NULL; + parcMemory_Deallocate((void **) &ops); + *opsPtr = NULL; +} + +static bool +mockIoOperations_Send(MetisIoOperations *ops, const CPIAddress *nexthop, MetisMessage *message) +{ + MockIoOperationsData *data = (MockIoOperationsData *) metisIoOperations_GetClosure(ops); + data->sendCount++; + + if (message) { + if (data->lastMessage) { + metisMessage_Release(&data->lastMessage); + } + + data->lastMessage = metisMessage_Acquire(message); + } + + return data->sendResult; +} + +static const CPIAddress * +mockIoOperations_GetRemoteAddress(const MetisIoOperations *ops) +{ + MockIoOperationsData *data = (MockIoOperationsData *) metisIoOperations_GetClosure(ops); + data->getRemoteAddressCount++; + return metisAddressPair_GetRemote(data->addressPair); +} + +static const MetisAddressPair * +mockIoOperations_GetAddressPair(const MetisIoOperations *ops) +{ + MockIoOperationsData *data = (MockIoOperationsData *) metisIoOperations_GetClosure(ops); + data->getAddressPairCount++; + return data->addressPair; +} + +static bool +mockIoOperations_IsUp(const MetisIoOperations *ops) +{ + MockIoOperationsData *data = (MockIoOperationsData *) metisIoOperations_GetClosure(ops); + data->isUpCount++; + return data->isUp; +} + +static bool +mockIoOperations_IsLocal(const MetisIoOperations *ops) +{ + MockIoOperationsData *data = (MockIoOperationsData *) metisIoOperations_GetClosure(ops); + data->isLocalCount++; + return data->isLocal; +} + + +static unsigned +mockIoOperations_GetConnectionId(const MetisIoOperations *ops) +{ + MockIoOperationsData *data = (MockIoOperationsData *) metisIoOperations_GetClosure(ops); + data->getConnectionIdCount++; + return data->id; +} + +static void +mockIoOperations_Destroy(MetisIoOperations **opsPtr) +{ + MockIoOperationsData *data = (MockIoOperationsData *) (*opsPtr)->closure; + data->destroyCount++; + *opsPtr = NULL; +} + +static CPIConnectionType +mockIoOperations_GetConnectionType(const MetisIoOperations *ops) +{ + MockIoOperationsData *data = (MockIoOperationsData *) metisIoOperations_GetClosure(ops); + data->getConnectionTypeCount++; + return data->connType; +} + +static const void * +mockIoOperations_Class(const MetisIoOperations *ops) +{ + MockIoOperationsData *data = (MockIoOperationsData *) metisIoOperations_GetClosure(ops); + data->classCount++; + return __FILE__; +} +#endif // Metis_testrig_MetisIoOperations_h |