aboutsummaryrefslogtreecommitdiffstats
path: root/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_ConnectionTable.c
diff options
context:
space:
mode:
Diffstat (limited to 'libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_ConnectionTable.c')
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_ConnectionTable.c309
1 files changed, 309 insertions, 0 deletions
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_ConnectionTable.c b/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_ConnectionTable.c
new file mode 100644
index 00000000..d77f47c0
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/core/test/test_rta_ConnectionTable.c
@@ -0,0 +1,309 @@
+/*
+ * 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 "../rta_ConnectionTable.c"
+#include "../rta_ProtocolStack.c"
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+
+LONGBOW_TEST_RUNNER(rta_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(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(rta_ConnectionTable)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(rta_ConnectionTable)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, rtaConnectionTable_AddConnection);
+ LONGBOW_RUN_TEST_CASE(Global, rtaConnectionTable_AddConnection_TooMany);
+ LONGBOW_RUN_TEST_CASE(Global, rtaConnectionTable_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, rtaConnectionTable_GetByApiFd);
+ LONGBOW_RUN_TEST_CASE(Global, rtaConnectionTable_GetByTransportFd);
+ LONGBOW_RUN_TEST_CASE(Global, rtaConnectionTable_Remove);
+ LONGBOW_RUN_TEST_CASE(Global, rtaConnectionTable_RemoveByStack);
+}
+
+typedef struct test_data {
+ PARCRingBuffer1x1 *commandRingBuffer;
+ PARCNotifier *commandNotifier;
+
+ RtaFramework *framework;
+
+ // in some tests we use two protocol stacks
+ RtaProtocolStack *stack_a;
+ RtaProtocolStack *stack_b;
+} TestData;
+
+static RtaConnection *
+createConnection(RtaProtocolStack *stack, int api_fd, int transport_fd)
+{
+ // -------
+ // Create a connection to use in the table
+ PARCJSON *params = parcJSON_ParseString("{}");
+ RtaCommandOpenConnection *openConnection = rtaCommandOpenConnection_Create(stack->stack_id, api_fd, transport_fd, params);
+
+ // Create a connection that goes in the connection table
+ RtaConnection *conn = rtaConnection_Create(stack, openConnection);
+ assertNotNull(conn, "Got null connection from rtaConnection_Create");
+
+ rtaCommandOpenConnection_Release(&openConnection);
+ parcJSON_Release(&params);
+ return conn;
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+
+ // ---------------------------
+ // To test a connection table, we need to create a Framework and a Protocol stack
+
+ data->commandRingBuffer = parcRingBuffer1x1_Create(128, NULL);
+ data->commandNotifier = parcNotifier_Create();
+
+ data->framework = rtaFramework_Create(data->commandRingBuffer, data->commandNotifier);
+
+ // fake out a protocol stack
+ data->stack_a = parcMemory_AllocateAndClear(sizeof(RtaProtocolStack));
+ assertNotNull(data->stack_a, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(RtaProtocolStack));
+ data->stack_a->stack_id = 1;
+ data->stack_a->framework = data->framework;
+
+ // fake out a protocol stack
+ data->stack_b = parcMemory_AllocateAndClear(sizeof(RtaProtocolStack));
+ assertNotNull(data->stack_b, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(RtaProtocolStack));
+ data->stack_b->stack_id = 2;
+ data->stack_b->framework = data->framework;
+
+ longBowTestCase_SetClipBoardData(testCase, data);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ // now cleanup everything
+ rtaFramework_Destroy(&data->framework);
+ parcNotifier_Release(&data->commandNotifier);
+ parcRingBuffer1x1_Release(&data->commandRingBuffer);
+
+ parcMemory_Deallocate((void **) &(data->stack_a));
+ parcMemory_Deallocate((void **) &(data->stack_b));
+ parcMemory_Deallocate((void **) &data);
+
+ 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;
+}
+
+/**
+ * Destroy the table before destroying the connection
+ */
+LONGBOW_TEST_CASE(Global, rtaConnectionTable_AddConnection)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ RtaConnection *conn = createConnection(data->stack_a, 2, 3);
+
+ // This is the part we want to test.
+ RtaConnectionTable *table = rtaConnectionTable_Create(1000, rtaConnection_Destroy);
+ rtaConnectionTable_AddConnection(table, conn);
+
+ assertTrue(table->count_elements == 1, "Incorrect table size, expected %d got %zu", 1, table->count_elements);
+ rtaConnectionTable_Destroy(&table);
+}
+
+
+/**
+ * Create a connection table with just 1 connection and make sure table
+ * does the right thing on overflow
+ */
+LONGBOW_TEST_CASE(Global, rtaConnectionTable_AddConnection_TooMany)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ RtaConnection *conn = createConnection(data->stack_a, 2, 3);
+
+ int res;
+
+ // create the table with size 1
+ RtaConnectionTable *table = rtaConnectionTable_Create(1, rtaConnection_Destroy);
+ res = rtaConnectionTable_AddConnection(table, conn);
+ assertTrue(res == 0, "Got non-zero return %d", res);
+ assertTrue(table->count_elements == 1, "Incorrect table size, expected %d got %zu", 1, table->count_elements);
+
+ // add the second connection, should return failure
+ res = rtaConnectionTable_AddConnection(table, conn);
+ assertTrue(res == -1, "Should have failed, expecting -1, got %d", res);
+
+ rtaConnectionTable_Destroy(&table);
+}
+
+
+LONGBOW_TEST_CASE(Global, rtaConnectionTable_Create_Destroy)
+{
+ size_t beforeBalance = parcMemory_Outstanding();
+ RtaConnectionTable *table = rtaConnectionTable_Create(1000, rtaConnection_Destroy);
+ assertTrue(table->max_elements == 1000, "Initialized with wrong number of elements");
+ rtaConnectionTable_Destroy(&table);
+ size_t afterBalance = parcMemory_Outstanding();
+ assertTrue(beforeBalance == afterBalance, "Memory imbalance after create/destroy");
+}
+
+LONGBOW_TEST_CASE(Global, rtaConnectionTable_GetByApiFd)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ RtaConnection *conn = createConnection(data->stack_a, 2, 3);
+
+ RtaConnectionTable *table = rtaConnectionTable_Create(1000, rtaConnection_Destroy);
+ rtaConnectionTable_AddConnection(table, conn);
+
+ RtaConnection *test;
+ test = rtaConnectionTable_GetByApiFd(table, 2);
+ assertTrue(test == conn, "Got wrong connection, expecting %p got %p", (void *) conn, (void *) test);
+
+ test = rtaConnectionTable_GetByApiFd(table, 3);
+ assertTrue(test == NULL, "Got wrong connection, expecting %p got %p", NULL, (void *) test);
+
+ test = rtaConnectionTable_GetByApiFd(table, 4);
+ assertTrue(test == NULL, "Got wrong connection, expecting %p got %p", NULL, (void *) test);
+
+ rtaConnectionTable_Destroy(&table);
+}
+
+LONGBOW_TEST_CASE(Global, rtaConnectionTable_GetByTransportFd)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ RtaConnection *conn = createConnection(data->stack_a, 2, 3);
+
+ RtaConnectionTable *table = rtaConnectionTable_Create(1000, rtaConnection_Destroy);
+ rtaConnectionTable_AddConnection(table, conn);
+
+ RtaConnection *test;
+ test = rtaConnectionTable_GetByTransportFd(table, 2);
+ assertTrue(test == NULL, "Got wrong connection, expecting %p got %p", NULL, (void *) test);
+
+ test = rtaConnectionTable_GetByTransportFd(table, 3);
+ assertTrue(test == conn, "Got wrong connection, expecting %p got %p", (void *) conn, (void *) test);
+
+ test = rtaConnectionTable_GetByTransportFd(table, 4);
+ assertTrue(test == NULL, "Got wrong connection, expecting %p got %p", NULL, (void *) test);
+
+
+ rtaConnectionTable_Destroy(&table);
+}
+
+/**
+ * We create two connections and make sure that when we remove one the other
+ * is still in the table
+ */
+LONGBOW_TEST_CASE(Global, rtaConnectionTable_Remove)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ int res;
+ int a_pair[2];
+ int b_pair[2];
+
+ // we have to use actual socket pairs in this test because Remove will destroy
+ // the last copy of the connection and call close() on the sockets.
+ socketpair(PF_LOCAL, SOCK_STREAM, 0, a_pair);
+ socketpair(PF_LOCAL, SOCK_STREAM, 0, b_pair);
+
+ RtaConnectionTable *table = rtaConnectionTable_Create(1000, rtaConnection_Destroy);
+
+ RtaConnection *conn_a = createConnection(data->stack_a, a_pair[0], a_pair[1]);
+ rtaConnectionTable_AddConnection(table, conn_a);
+
+ RtaConnection *conn_b = createConnection(data->stack_b, b_pair[0], b_pair[1]);
+ rtaConnectionTable_AddConnection(table, conn_b);
+
+ assertTrue(table->count_elements == 2, "Wrong element count");
+
+ res = rtaConnectionTable_Remove(table, conn_b);
+ assertTrue(res == 0, "Got error from rtaConnectionTable_Remove: %d", res);
+ assertTrue(table->count_elements == 1, "Wrong element count");
+
+ RtaConnection *test = rtaConnectionTable_GetByApiFd(table, a_pair[0]);
+ assertNotNull(test, "Could not retrieve connection that was supposed to still be there");
+
+ rtaConnectionTable_Destroy(&table);
+}
+
+/**
+ * Create two connections, they are in different protocol stacks. Remove one by
+ * stack id and make sure the other is still in the table
+ */
+LONGBOW_TEST_CASE(Global, rtaConnectionTable_RemoveByStack)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ int res;
+ int a_pair[2];
+ int b_pair[2];
+
+ // we have to use actual socket pairs in this test because Remove will destroy
+ // the last copy of the connection and call close() on the sockets.
+ socketpair(PF_LOCAL, SOCK_STREAM, 0, a_pair);
+ socketpair(PF_LOCAL, SOCK_STREAM, 0, b_pair);
+
+ RtaConnectionTable *table = rtaConnectionTable_Create(1000, rtaConnection_Destroy);
+
+ RtaConnection *conn_a = createConnection(data->stack_a, a_pair[0], a_pair[1]);
+ rtaConnectionTable_AddConnection(table, conn_a);
+
+ RtaConnection *conn_b = createConnection(data->stack_b, b_pair[0], b_pair[1]);
+ rtaConnectionTable_AddConnection(table, conn_b);
+
+ // now remove a connection by stack id
+
+ res = rtaConnectionTable_RemoveByStack(table, data->stack_a->stack_id);
+ assertTrue(res == 0, "Got error from rtaConnectionTable_RemoveByStack: %d", res);
+ assertTrue(table->count_elements == 1, "Wrong element count");
+
+ RtaConnection *test = rtaConnectionTable_GetByApiFd(table, b_pair[0]);
+ assertNotNull(test, "Could not retrieve connection that was supposed to still be there");
+
+ rtaConnectionTable_Destroy(&table);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(rta_ConnectionTable);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}