summaryrefslogtreecommitdiffstats
path: root/libccnx-transport-rta/ccnx/transport/transport_rta/test
diff options
context:
space:
mode:
Diffstat (limited to 'libccnx-transport-rta/ccnx/transport/transport_rta/test')
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/test/.gitignore19
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/test/CMakeLists.txt13
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/test/README17
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/test/test_multi_connections.c424
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/test/test_rta_Commands.c381
-rw-r--r--libccnx-transport-rta/ccnx/transport/transport_rta/test/test_rta_Transport.c701
6 files changed, 1555 insertions, 0 deletions
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/test/.gitignore b/libccnx-transport-rta/ccnx/transport/transport_rta/test/.gitignore
new file mode 100644
index 00000000..90005943
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/test/.gitignore
@@ -0,0 +1,19 @@
+rtatest
+test_bent_pipe
+test_component_Ccnd_Registrar
+test_component_Codec_Ccnb
+test_component_Codec_Tlv_Hmac
+test_connector_Api
+test_connector_Forwarder_Ccnd
+test_connector_Forwarder_Flan
+test_connector_Forwarder_Local
+test_fc_vegas
+test_multi_connections
+test_rta_Commands
+test_rta_ConnectionTable
+test_rta_Framework
+test_rta_Framework_Commands
+test_rta_WebService
+test_system_passthrough
+test_connector_Forwarder_Metis
+
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/test/CMakeLists.txt b/libccnx-transport-rta/ccnx/transport/transport_rta/test/CMakeLists.txt
new file mode 100644
index 00000000..c52b0166
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/test/CMakeLists.txt
@@ -0,0 +1,13 @@
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+set(TestsExpectedToPass
+ test_multi_connections
+ test_rta_Transport
+)
+
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/test/README b/libccnx-transport-rta/ccnx/transport/transport_rta/test/README
new file mode 100644
index 00000000..8a325828
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/test/README
@@ -0,0 +1,17 @@
+/*
+ * 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.
+ *
+ */
+
+These are system tests, not specific to any one component or connector
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/test/test_multi_connections.c b/libccnx-transport-rta/ccnx/transport/transport_rta/test/test_multi_connections.c
new file mode 100644
index 00000000..8f0051a0
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/test/test_multi_connections.c
@@ -0,0 +1,424 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <sys/un.h>
+#include <strings.h>
+#include <fcntl.h>
+#include <limits.h>
+
+#include <LongBow/unit-test.h>
+
+
+#include <ccnx/api/control/cpi_ControlMessage.h>
+#include <ccnx/common/ccnx_ContentObject.h>
+
+#include <parc/security/parc_Pkcs12KeyStore.h>
+#include <parc/security/parc_PublicKeySigner.h>
+#include <parc/security/parc_Security.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <ccnx/transport/transport_rta/config/config_All.h>
+#include <ccnx/transport/transport_rta/core/rta_Framework.h>
+#include <ccnx/transport/transport_rta/core/rta_Framework_Commands.c>
+#include <ccnx/transport/transport_rta/core/rta_Framework_NonThreaded.h>
+
+#include "../../test_tools/bent_pipe.h"
+#include <ccnx/transport/test_tools/traffic_tools.h>
+
+static const char local_name[] = "/tmp/beta";
+static const char alice_keystore_name[] = "/tmp/alice_keystore";
+static const char bob_keystore_name[] = "/tmp/bob_keystore";
+
+static int alice_fd;
+static int bob_fd;
+static TransportContext *transport_context;
+static CCNxTransportConfig *alice_params;
+static CCNxTransportConfig *bob_params;
+
+// reflector for FWD_LOCAL
+static BentPipeState *bentpipe;
+
+static int rnd_fd;
+
+// for statistics
+static double total_delay;
+static double total_bytes_per_sec;
+static unsigned item_count;
+
+// ======================================================
+
+static CCNxTransportConfig *
+MultipleConnections_createParams(const char *local_name, const char *keystore_name, const char *keystore_passwd, const char *nonce)
+{
+ assertNotNull(local_name, "Got null keystore name\n");
+ assertNotNull(keystore_name, "Got null keystore name\n");
+ assertNotNull(keystore_passwd, "Got null keystore passwd\n");
+
+ CCNxStackConfig *stackConfig = ccnxStackConfig_Create();
+
+ apiConnector_ProtocolStackConfig(
+ tlvCodec_ProtocolStackConfig(
+ localForwarder_ProtocolStackConfig(
+ protocolStack_ComponentsConfigArgs(stackConfig,
+ apiConnector_GetName(),
+ tlvCodec_GetName(),
+ localForwarder_GetName(),
+ NULL)
+ )));
+
+ CCNxConnectionConfig *connConfig = apiConnector_ConnectionConfig(
+ tlvCodec_ConnectionConfig(
+ localForwarder_ConnectionConfig(ccnxConnectionConfig_Create(), local_name)));
+
+ publicKeySigner_ConnectionConfig(connConfig, keystore_name, keystore_passwd);
+
+
+ // add the special nonce
+ PARCJSONValue *value = parcJSONValue_CreateFromCString(nonce);
+ ccnxStackConfig_Add(stackConfig, "nonce", value);
+ parcJSONValue_Release(&value);
+
+ CCNxTransportConfig *result = ccnxTransportConfig_Create(stackConfig, connConfig);
+ ccnxStackConfig_Release(&stackConfig);
+
+ return result;
+}
+
+/**
+ * @function sendRandomObject
+ * @abstract Sends a content object over the given socket.
+ * @discussion
+ * The payload of the content object is a "struct timeval" for timing purposes.
+ *
+ * @param Transport socket to use
+ * @return A copy of the content object sent
+ */
+static CCNxContentObject *
+sendRandomObject(int output_fd, int fixed_size)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+
+ if (fixed_size < (int) sizeof(tv)) {
+ fixed_size = sizeof(tv);
+ }
+
+ uint8_t *buffer = parcMemory_Allocate(fixed_size);
+ assertNotNull(buffer, "parcMemory_Allocate(%d) returned NULL", fixed_size);
+ memcpy(buffer, (uint8_t *) &tv, sizeof(tv));
+
+ PARCBuffer *contents = parcBuffer_Flip(parcBuffer_CreateFromArray(buffer, fixed_size));
+ CCNxContentObject *object = trafficTools_CreateContentObjectWithPayload(contents);
+ parcBuffer_Release(&contents);
+
+ // Return value not checked.
+ // This creates a reference to object, so we still hold the memory and can return it
+ CCNxMetaMessage *meta = ccnxMetaMessage_CreateFromContentObject(object);
+ Transport_Send(output_fd, meta);
+ ccnxMetaMessage_Release(&meta);
+
+ parcMemory_Deallocate((void **) &buffer);
+
+ // truth_co and truth_msg will be freed by Transport_Send
+ return object;
+}
+
+/**
+ * @function recvAndCompare
+ * @abstract Block on receiving a message on the input_fd, then assert its the same as the truth_obj.
+ * @discussion
+ * <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ */
+static bool
+recvAndCompare(int input_fd, CCNxContentObject *truth_obj)
+{
+ struct timeval now, *then, delta;
+
+ CCNxMetaMessage *test_msg;
+ int res = Transport_Recv(input_fd, &test_msg);
+
+ assertTrue(res == 0, "got error from Transport_Recv (%d)", res);
+
+ // We can't directly compare the two dictionaries with CCNxTlvDictionary_Equals(),
+ // because the test_obj that we read in was signed in the Transport when
+ // it was sent. So the dictionaries are different.
+
+ // So, instead, compare the payload - which should have the time at which the ContentObject
+ // was created.
+
+ CCNxContentObject *testObject = ccnxMetaMessage_GetContentObject(test_msg);
+ PARCBuffer *contentsA = ccnxContentObject_GetPayload(testObject);
+ PARCBuffer *contentsB = ccnxContentObject_GetPayload(truth_obj);
+ assertTrue(parcBuffer_Equals(contentsA, contentsB), "Payloads do not compare");
+
+ then = (struct timeval *) parcBuffer_Overlay(contentsA, 0);
+
+ gettimeofday(&now, NULL);
+ timersub(&now, then, &delta);
+
+ double delay = delta.tv_sec + 1E-6 * delta.tv_usec;
+ double bytes_per_sec = parcBuffer_Remaining(parcBuffer_Rewind(contentsA)) / delay;
+
+ total_delay += delay;
+ total_bytes_per_sec += bytes_per_sec;
+ item_count++;
+
+ ccnxMetaMessage_Release(&test_msg);
+ return true;
+}
+
+static void
+assertConnectionOpen(int fd)
+{
+ // wait for the CONNECTION_OPEN messages
+ CCNxMetaMessage *firstMessage;
+ Transport_Recv(fd, &firstMessage);
+
+ assertTrue(ccnxMetaMessage_IsControl(firstMessage), "Expected first message to be a control message");
+
+ CCNxControl *control = ccnxMetaMessage_GetControl(firstMessage);
+
+ if (ccnxControl_IsNotification(control)) {
+ NotifyStatus *status = ccnxControl_GetNotifyStatus(control);
+
+ assertTrue(notifyStatus_IsConnectionOpen(status), "Expected notifyStatus_IsConnectionOpen to be true");
+
+ notifyStatus_Release(&status);
+ }
+
+ ccnxMetaMessage_Release(&firstMessage);
+}
+
+static void
+stackSetup(const char *alice_nonce, const char *bob_nonce)
+{
+ unlink(local_name);
+
+ bentpipe = bentpipe_Create(local_name);
+ bentpipe_SetChattyOutput(bentpipe, false);
+ bentpipe_Start(bentpipe);
+
+ transport_context = Transport_Create(TRANSPORT_RTA);
+
+ assertNotNull(transport_context, "transportRta_Create() returned null");
+
+ unlink(alice_keystore_name);
+ unlink(bob_keystore_name);
+
+ bool success = parcPkcs12KeyStore_CreateFile(alice_keystore_name, "23456", "alice", 1024, 30);
+ assertTrue(success, "parcPkcs12Store_CreateFile() failed.");
+ success = parcPkcs12KeyStore_CreateFile(bob_keystore_name, "34567", "bob", 2048, 15);
+ assertTrue(success, "parcPkcs12Store_CreateFile() failed.");
+
+ alice_params = MultipleConnections_createParams(local_name, alice_keystore_name, "23456", alice_nonce);
+ bob_params = MultipleConnections_createParams(local_name, bob_keystore_name, "34567", bob_nonce);
+
+ // open a connection, this will cause accpet() to fire
+ alice_fd = Transport_Open(alice_params);
+ bob_fd = Transport_Open(bob_params);
+
+ assertFalse(alice_fd < 0, "Transport_Open returned error");
+ assertFalse(bob_fd < 0, "Transport_Open returned error");
+
+ assertConnectionOpen(alice_fd);
+ assertConnectionOpen(bob_fd);
+}
+
+static void
+stackTearDown(const char *alice_nonce, const char *bob_nonce)
+{
+ assertTrue(unlink(alice_keystore_name) == 0 || errno == ENOENT,
+ "Unable to unlink the file %s: %s", alice_keystore_name, strerror(errno));
+
+ assertTrue(unlink(bob_keystore_name) == 0 || errno == ENOENT,
+ "Unable to unlink the file %s: %s", bob_keystore_name, strerror(errno));
+
+ Transport_Destroy(&transport_context);
+ bentpipe_Stop(bentpipe);
+ bentpipe_Destroy(&bentpipe);
+
+ ccnxTransportConfig_Destroy(&alice_params);
+ ccnxTransportConfig_Destroy(&bob_params);
+}
+
+#include <parc/algol/parc_Object.h>
+
+/**
+ * @function ping
+ * @abstract Send a message from one socket to another socket
+ * @discussion
+ * Send a content object from one socket to another, then esure the
+ * unsigned parts of the received message compare to the sent message.
+ *
+ * There's a minimum size (sizeof struct timeval). If the fixed_size is
+ * larger than that minimum, we'll pad out to the fixed size.
+ *
+ * @param fixed_size is the payload content size.
+ * @return <#return#>
+ */
+static bool
+ping(int from_fd, int to_fd, int fixed_size)
+{
+ CCNxContentObject *object = sendRandomObject(from_fd, fixed_size);
+ bool success = recvAndCompare(to_fd, object);
+ assertTrue(success, "sent and received didn't compare!\n");
+ ccnxContentObject_Release(&object);
+ return success;
+}
+/**
+ * use -1 for random size, othewise anything larger than 16 works
+ * for the payload size
+ */
+static void
+playPingPong(int fixed_size)
+{
+ int loops = 10;
+ while (loops-- > 0) {
+ // send down alice and up bob, then bob to alice
+ ping(alice_fd, bob_fd, fixed_size);
+ ping(bob_fd, alice_fd, fixed_size);
+ }
+}
+
+// ======================================================
+
+
+LONGBOW_TEST_RUNNER(MultipleConnections)
+{
+ LONGBOW_RUN_TEST_FIXTURE(SameStack);
+ LONGBOW_RUN_TEST_FIXTURE(DifferentStacks);
+}
+
+LONGBOW_TEST_RUNNER_SETUP(MultipleConnections)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ rnd_fd = open("/dev/urandom", O_RDONLY);
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_RUNNER_TEARDOWN(MultipleConnections)
+{
+ close(rnd_fd);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
+// $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
+
+/*
+ * Same Stack tests multiple connections within the same
+ * protocol stack
+ */
+
+LONGBOW_TEST_FIXTURE(SameStack)
+{
+ LONGBOW_RUN_TEST_CASE(SameStack, alice_bob_pingpong);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(SameStack)
+{
+ parcSecurity_Init();
+ stackSetup("apple", "apple");
+
+ total_delay = total_bytes_per_sec = 0.0;
+ item_count = 0;
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(SameStack)
+{
+ longBowDebug("average delay %.6f sec, avg bytes/sec %.3f\n",
+ total_delay / item_count, total_bytes_per_sec / item_count);
+
+ stackTearDown("apple", "apple");
+
+ parcSecurity_Fini();
+
+ if (parcMemory_Outstanding() != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(SameStack, alice_bob_pingpong)
+{
+ playPingPong(8192);
+}
+
+// $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
+// $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
+
+/*
+ * DifferentStacks tests multiple connections through
+ * different stacks in the same transport
+ */
+
+LONGBOW_TEST_FIXTURE(DifferentStacks)
+{
+ LONGBOW_RUN_TEST_CASE(DifferentStacks, alice_bob_pingpong);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(DifferentStacks)
+{
+ parcSecurity_Init();
+ stackSetup("apple", "oranges");
+ total_delay = total_bytes_per_sec = 0.0;
+ item_count = 0;
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(DifferentStacks)
+{
+ stackTearDown("apple", "oranges");
+
+ parcSecurity_Fini();
+
+ if (parcMemory_Outstanding() != 0) {
+ printf("('%s' leaks memory by %d (allocs - frees)) ", longBowTestCase_GetName(testCase), parcMemory_Outstanding());
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(DifferentStacks, alice_bob_pingpong)
+{
+ playPingPong(-1);
+}
+
+// $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
+// $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(MultipleConnections);
+ exit(longBowMain(argc, argv, testRunner, NULL));
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/test/test_rta_Commands.c b/libccnx-transport-rta/ccnx/transport/transport_rta/test/test_rta_Commands.c
new file mode 100644
index 00000000..4f4d7cb0
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/test/test_rta_Commands.c
@@ -0,0 +1,381 @@
+/*
+ * 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_Commands.c"
+
+#include "../core/components.h"
+#include <ccnx/transport/transport_rta/config/config_All.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <LongBow/unit-test.h>
+#include <strings.h>
+
+static TransportConfig *
+Test_createParams(const char *local_name)
+{
+ assertNotNull(local_name, "%s got null keystore name\n", __func__);
+
+ ConnectionConfig *connConfig = apiConnector_ConnectionConfig(localForwarder_ConnectionConfig(ccnxConnectionConfig_Create(), local_name));
+
+ CCNxStackConfig *stackConfig = apiConnector_ProtocolStackConfig(
+ localForwarder_ProtocolStackConfig(
+ protocolStack_ComponentsConfigArgs(
+ ccnxStackConfig_Create(), apiConnector_GetName(), localForwarder_GetName(), NULL)));
+
+ return transportConfig_Create(stackConfig, connConfig);
+}
+
+LONGBOW_TEST_RUNNER(rta_Commands)
+{
+ // 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_Commands)
+{
+ 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(rta_Commands)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_Close);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_CreateStack);
+
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_DestroyStack);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_GetClose);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_GetCreateStack);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_GetDestroyStack);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_GetOpen);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_GetType);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_Open);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_Read_Write);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_Shutdown);
+ LONGBOW_RUN_TEST_CASE(Global, rtaCommand_CreateTransmitStatistics);
+ LONGBOW_RUN_TEST_CASE(Global, CommandTransmitStatistics_FromJSON);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_Close)
+{
+ CommandClose commmandClose = { .api_fd = 7 };
+ char *truth = "{ \"RTA\" : { \"CLOSE\" : 7 } }";
+ PARCJSON *truth_json = parcJSON_ParseString(truth);
+ char *truth_formatted = ccnxJson_ToString(truth_json);
+ char *test;
+
+ RtaCommand *command = rtaCommand_Close(commmandClose);
+
+ assertTrue(command->type == RTA_COMMAND_CLOSE, "Type not RTA_COMMAND_CLOSE");
+
+ test = ccnxJson_ToString(command->command);
+ assertTrue(strcasecmp(test, truth_formatted) == 0,
+ "JSON does not match\nexpected: %s\ngot: %s\n",
+ truth_formatted, test);
+
+ rtaCommand_Destroy(&command);
+ parcJSON_Release(&truth_json);
+ parcMemory_Deallocate((void **) &test);
+ parcMemory_Deallocate((void **) &truth_formatted);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_CreateStack)
+{
+ TransportConfig *params = Test_createParams("/tmp/fwd");
+ CCNxStackConfig *stackConfig = transportConfig_GetProtocolStackConfig(params);
+ char *params_str = ccnxJson_ToString(ccnxStackConfig_GetJson(stackConfig));
+
+ CommandCreateStack commandCreateStack = { .stack_id = 9, .params = ccnxStackConfig_GetJson(stackConfig) };
+ char *truth = "{ \"RTA\" : { \"CREATE STACK\" : 9, \"PARAMS\" : %s } }";
+ char buffer[1024];
+
+ sprintf(buffer, truth, params_str);
+
+ PARCJSON *truth_json = parcJSON_ParseString(buffer);
+ char *truth_formatted = ccnxJson_ToString(truth_json);
+ char *test;
+
+ RtaCommand *command = rtaCommand_CreateStack(commandCreateStack);
+
+ assertTrue(command->type == RTA_COMMAND_CREATESTACK, "Type not RTA_COMMAND_CREATESTACK");
+
+ test = ccnxJson_ToString(command->command);
+ assertTrue(strcasecmp(test, truth_formatted) == 0,
+ "JSON does not match\nexpected: %s\ngot: %s\n",
+ truth_formatted, test);
+
+ rtaCommand_Destroy(&command);
+ parcJSON_Release(&truth_json);
+ transportConfig_Destroy(&params);
+ parcMemory_Deallocate((void **) &test);
+ parcMemory_Deallocate((void **) &truth_formatted);
+ parcMemory_Deallocate((void **) &params_str);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_DestroyStack)
+{
+ CommandDestroyStack commandDestroyStack = { .stack_id = 2 };
+ char *truth = "{ \"RTA\" : { \"DESTROY STACK\" : 2 } }";
+ PARCJSON *truth_json = parcJSON_ParseString(truth);
+ char *truth_formatted = ccnxJson_ToString(truth_json);
+ char *test;
+
+ RtaCommand *command = rtaCommand_DestroyStack(commandDestroyStack);
+
+ assertTrue(command->type == RTA_COMMAND_DESTROYSTACK, "Type not RTA_COMMAND_DESTROYSTACK");
+
+ test = ccnxJson_ToString(command->command);
+ assertTrue(strcasecmp(test, truth_formatted) == 0,
+ "JSON does not match\nexpected: %s\ngot: %s\n",
+ truth_formatted, test);
+
+ rtaCommand_Destroy(&command);
+ parcJSON_Release(&truth_json);
+ parcMemory_Deallocate((void **) &test);
+ parcMemory_Deallocate((void **) &truth_formatted);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_GetClose)
+{
+ CommandClose commmandClose = { .api_fd = 7 };
+ CommandClose test;
+
+ RtaCommand *command = rtaCommand_Close(commmandClose);
+ rtaCommand_GetClose(command, &test);
+ assertTrue(memcmp(&commmandClose, &test, sizeof(CommandClose)) == 0, "structures do not match");
+ rtaCommand_Destroy(&command);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_GetCreateStack)
+{
+ TransportConfig *params = Test_createParams("/tmp/fwd");
+ CCNxStackConfig *stackConfig = transportConfig_GetProtocolStackConfig(params);
+
+ CommandCreateStack commandCreateStack = { .stack_id = 9, .params = ccnxStackConfig_GetJson(stackConfig) };
+ CommandCreateStack test;
+
+ RtaCommand *command = rtaCommand_CreateStack(commandCreateStack);
+ rtaCommand_GetCreateStack(command, &test);
+
+ assertTrue(test.stack_id == 9, "Wrong stack id, expected %d got %d", 9, test.stack_id);
+
+ char *truth_params = ccnxJson_ToString(ccnxStackConfig_GetJson(stackConfig));
+ char *test_params = ccnxJson_ToString(test.params);
+ assertTrue(strcasecmp(truth_params, test_params) == 0, "params strings did not match");
+
+ parcMemory_Deallocate((void **) &truth_params);
+ parcMemory_Deallocate((void **) &test_params);
+ rtaCommand_Destroy(&command);
+ transportConfig_Destroy(&params);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_GetDestroyStack)
+{
+ CommandDestroyStack commandDestroyStack = { .stack_id = 133434 };
+ CommandDestroyStack test;
+
+ RtaCommand *command = rtaCommand_DestroyStack(commandDestroyStack);
+ rtaCommand_GetDestroyStack(command, &test);
+ assertTrue(memcmp(&commandDestroyStack, &test, sizeof(CommandDestroyStack)) == 0, "structures do not match");
+ rtaCommand_Destroy(&command);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_GetOpen)
+{
+ TransportConfig *params = Test_createParams("/tmp/fwd");
+ CCNxStackConfig *stackConfig = transportConfig_GetProtocolStackConfig(params);
+
+ CommandOpen commandOpen = { .stack_id = 9, .api_fd = 77, .transport_fd = 102, .params = ccnxStackConfig_GetJson(stackConfig) };
+ CommandOpen test;
+ RtaCommand *command = rtaCommand_Open(commandOpen);
+ rtaCommand_GetOpen(command, &test);
+
+ assertTrue(test.stack_id == 9, "Wrong stack id, expected %d got %d", 9, test.stack_id);
+ assertTrue(test.api_fd == 77, "Wrong api_fd, expected %d got %d", 77, test.api_fd);
+ assertTrue(test.transport_fd == 102, "Wrong transport_fd, expected %d got %d", 102, test.transport_fd);
+
+ char *truth_params = ccnxJson_ToString(ccnxStackConfig_GetJson(stackConfig));
+ char *test_params = ccnxJson_ToString(test.params);
+ assertTrue(strcasecmp(truth_params, test_params) == 0, "params strings did not match");
+
+ parcMemory_Deallocate((void **) &truth_params);
+ parcMemory_Deallocate((void **) &test_params);
+ rtaCommand_Destroy(&command);
+ transportConfig_Destroy(&params);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_GetType)
+{
+ CommandDestroyStack commandDestroyStack = { .stack_id = 2 };
+ RtaCommand *command = rtaCommand_DestroyStack(commandDestroyStack);
+ assertTrue(rtaCommand_GetType(command) == RTA_COMMAND_DESTROYSTACK, "Type not RTA_COMMAND_DESTROYSTACK");
+ rtaCommand_Destroy(&command);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_Open)
+{
+ TransportConfig *params = Test_createParams("/tmp/fwd");
+ CCNxStackConfig *stackConfig = transportConfig_GetProtocolStackConfig(params);
+
+ char *params_str = ccnxJson_ToString(ccnxStackConfig_GetJson(stackConfig));
+
+ CommandOpen commandOpen = { .stack_id = 9, .api_fd = 77, .transport_fd = 102, .params = ccnxStackConfig_GetJson(stackConfig) };
+ char *truth = "{ \"RTA\" : { \"OPEN\" : [9, 77, 102], \"PARAMS\" : %s } }";
+ char buffer[1024];
+
+ sprintf(buffer, truth, params_str);
+
+ PARCJSON *truth_json = parcJSON_ParseString(buffer);
+ char *truth_formatted = ccnxJson_ToString(truth_json);
+ char *test;
+
+ RtaCommand *command = rtaCommand_Open(commandOpen);
+
+ assertTrue(command->type == RTA_COMMAND_OPEN, "Type not RTA_COMMAND_OPEN");
+
+ test = ccnxJson_ToString(command->command);
+ assertTrue(strcasecmp(test, truth_formatted) == 0,
+ "JSON does not match\nexpected: %s\ngot: %s\n",
+ truth_formatted, test);
+
+ rtaCommand_Destroy(&command);
+ parcJSON_Release(&truth_json);
+ transportConfig_Destroy(&params);
+ parcMemory_Deallocate((void **) &test);
+ parcMemory_Deallocate((void **) &truth_formatted);
+ parcMemory_Deallocate((void **) &params_str);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_Read_Write)
+{
+ int fds[2];
+ pipe(fds);
+
+ CommandDestroyStack commandDestroyStack = { .stack_id = 2 };
+ RtaCommand *command = rtaCommand_DestroyStack(commandDestroyStack);
+ rtaCommand_Write(command, fds[1]);
+ RtaCommand *test_command = rtaCommand_Read(fds[0]);
+ CommandDestroyStack test;
+ rtaCommand_GetDestroyStack(test_command, &test);
+ assertTrue(memcmp(&commandDestroyStack, &test, sizeof(commandDestroyStack)) == 0, "memcmp did not match");
+
+ rtaCommand_Destroy(&command);
+ rtaCommand_Destroy(&test_command);
+ close(fds[1]);
+ close(fds[0]);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_Shutdown)
+{
+ char *truth = "{ \"RTA\" : { \"SHUTDOWN\" : 1 } }";
+ PARCJSON *truth_json = parcJSON_ParseString(truth);
+ char *truth_formatted = ccnxJson_ToString(truth_json);
+ char *test;
+
+ RtaCommand *command = rtaCommand_Shutdown();
+
+ assertTrue(command->type == RTA_COMMAND_SHUTDOWN, "Type not RTA_COMMAND_SHUTDOWN");
+
+ test = ccnxJson_ToString(command->command);
+ assertTrue(strcasecmp(test, truth_formatted) == 0,
+ "JSON does not match\nexpected: %s\ngot: %s\n",
+ truth_formatted, test);
+
+ rtaCommand_Destroy(&command);
+ parcJSON_Release(&truth_json);
+ parcMemory_Deallocate((void **) &test);
+ parcMemory_Deallocate((void **) &truth_formatted);
+}
+
+LONGBOW_TEST_CASE(Global, rtaCommand_CreateTransmitStatistics)
+{
+ char *truth = "{ \"RTA\" : { \"TransmitStatistics\" : { \"fileName\": \"/tmp/foo\", \"timeval\" : { "
+ "\"seconds\" : 1, \"microseconds\": 2 } } } }\n";
+
+ PARCJSON *truth_json = parcJSON_ParseString(truth);
+ char *truth_formatted = ccnxJson_ToString(truth_json);
+
+ CommandTransmitStatistics transmitStatistics = {
+ .timeval = { .tv_sec = 1, .tv_usec = 2 },
+ .fileName = "/tmp/foo"
+ };
+
+ RtaCommand *command = CommandTransmitStatistics_ToRtaCommand(transmitStatistics);
+
+ assertTrue(command->type == RTA_COMMAND_TRANSMIT_STATISTICS,
+ "Expected RTA_COMMAND_TRANSMIT_STATISTICS, actual %d", command->type);
+
+ char *test = ccnxJson_ToString(command->command);
+ assertTrue(strcasecmp(test, truth_formatted) == 0,
+ "JSON does not match\nexpected: %s\ngot: %s\n",
+ truth_formatted, test);
+
+ rtaCommand_Destroy(&command);
+ parcJSON_Release(&truth_json);
+ parcMemory_Deallocate((void **) &test);
+ parcMemory_Deallocate((void **) &truth_formatted);
+}
+
+LONGBOW_TEST_CASE(Global, CommandTransmitStatistics_FromJSON)
+{
+ CommandTransmitStatistics transmitStatistics = {
+ .timeval = { .tv_sec = 1, .tv_usec = 2 },
+ .fileName = "/tmp/foo"
+ };
+ RtaCommand *command = CommandTransmitStatistics_ToRtaCommand(transmitStatistics);
+
+ CommandTransmitStatistics actual;
+ CommandTransmitStatistics_FromRtaCommand(command, &actual);
+
+ assertTrue(transmitStatistics.timeval.tv_sec == actual.timeval.tv_sec, "tv_sec failed to be equal");
+ assertTrue(transmitStatistics.timeval.tv_usec == actual.timeval.tv_usec, "tv_usec failed to be equal");
+ assertTrue(strcmp(transmitStatistics.fileName, actual.fileName) == 0, "fileName failed to be equal");
+
+ rtaCommand_Destroy(&command);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(rta_Commands);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libccnx-transport-rta/ccnx/transport/transport_rta/test/test_rta_Transport.c b/libccnx-transport-rta/ccnx/transport/transport_rta/test/test_rta_Transport.c
new file mode 100644
index 00000000..9f6f0611
--- /dev/null
+++ b/libccnx-transport-rta/ccnx/transport/transport_rta/test/test_rta_Transport.c
@@ -0,0 +1,701 @@
+/*
+ * 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_Transport.c"
+#include <ccnx/transport/transport_rta/config/config_All.h>
+#include <ccnx/transport/transport_rta/core/rta_Framework_private.h>
+#include <ccnx/transport/transport_rta/components/component_Testing.h>
+
+#include <ccnx/common/ccnx_WireFormatMessage.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <ccnx/transport/test_tools/traffic_tools.h>
+
+#include <LongBow/unit-test.h>
+
+typedef struct test_data {
+ RTATransport *transport;
+ CCNxMetaMessage *msg;
+} TestData;
+
+static TestData *
+_commonSetup(void)
+{
+ TestData *data = parcMemory_AllocateAndClear(sizeof(TestData));
+ assertNotNull(data, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(TestData));
+ data->transport = rtaTransport_Create();
+ return data;
+}
+
+static void
+_commonTeardown(TestData *data)
+{
+ rtaTransport_Destroy(&data->transport);
+ if (data->msg) {
+ ccnxMetaMessage_Release(&data->msg);
+ }
+
+ parcMemory_Deallocate((void **) &data);
+}
+
+static CCNxTransportConfig *
+createSimpleConfig(TestData *data)
+{
+ // API connector -> Testing Lower component
+
+ CCNxStackConfig *stackConfig =
+ testingLower_ProtocolStackConfig(apiConnector_ProtocolStackConfig(ccnxStackConfig_Create()));
+
+ CCNxConnectionConfig *connConfig =
+ testingLower_ConnectionConfig(
+ tlvCodec_ConnectionConfig(
+ apiConnector_ConnectionConfig(
+ ccnxConnectionConfig_Create())));
+
+ protocolStack_ComponentsConfigArgs(stackConfig, apiConnector_GetName(), testingLower_GetName(), NULL);
+
+ CCNxTransportConfig *result = ccnxTransportConfig_Create(stackConfig, connConfig);
+ ccnxStackConfig_Release(&stackConfig);
+ return result;
+}
+
+/**
+ * Peek inside the RTA framework's connection table
+ *
+ * We will look inside the RTA framework's thread to find a connection by the API_FD.
+ *
+ * @param [in] data The test data, holding the transport
+ * @param [in] api_fd The API FD to lookup
+ * @param [in] usec_timeout How long to busy wait looking in the connection table (micro seconds)
+ *
+ * @return NULL It was not in the table after the timeout period
+ * @return non-null The connection corresponding to api_fd
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static RtaConnection *
+lookupRtaConnectionInsideFramework(TestData *data, int api_fd, unsigned usec_timeout)
+{
+ // busy loop looking for connection to give RTA thread time to process it.
+ // Remember, we're operating in the "API" thread when issuing these commands.
+ struct timeval t0;
+ long timer_usec = 0;
+ gettimeofday(&t0, NULL);
+ bool timeout = false;
+ RtaConnection *conn = NULL;
+ while (conn == NULL && !timeout) {
+ usleep(500);
+ conn = rtaConnectionTable_GetByApiFd(data->transport->framework->connectionTable, api_fd);
+ struct timeval t1;
+ gettimeofday(&t1, NULL);
+ timersub(&t1, &t0, &t1);
+ timer_usec = t1.tv_sec * 1000000 + t1.tv_usec;
+ timeout = timer_usec > usec_timeout ? true : false;
+ }
+
+ if (conn) {
+ printf("Found connection %p after %.6f seconds\n", (void *) conn, timer_usec * 1E-6);
+ }
+
+ return conn;
+}
+
+/**
+ * Wait for a connection to go away
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static bool
+lookupNullRtaConnectionInsideFramework(TestData *data, int api_fd, unsigned usec_timeout)
+{
+ // busy loop looking for connection to give RTA thread time to process it.
+ // Remember, we're operating in the "API" thread when issuing these commands.
+ struct timeval t0;
+ long timer_usec = 0;
+ gettimeofday(&t0, NULL);
+ bool timeout = false;
+
+ // initialize to non-null
+ RtaConnection *conn = (void *) 1;
+ while (conn != NULL && !timeout) {
+ usleep(500);
+ conn = rtaConnectionTable_GetByApiFd(data->transport->framework->connectionTable, api_fd);
+ struct timeval t1;
+ gettimeofday(&t1, NULL);
+ timersub(&t1, &t0, &t1);
+ timer_usec = t1.tv_sec * 1000000 + t1.tv_usec;
+ timeout = timer_usec > usec_timeout ? true : false;
+ }
+
+ if (conn == NULL) {
+ printf("Found no connection %p after %.6f seconds\n", (void *) conn, timer_usec * 1E-6);
+ }
+
+ // if its null, return true
+ return (conn == NULL);
+}
+
+
+// ==================================================================================
+// Runner
+
+LONGBOW_TEST_RUNNER(rta_Transport)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Local);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(rta_Transport)
+{
+ 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(rta_Transport)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ==================================================================================
+// Global
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ // These are still static functions, but they are the function pointers used
+ // in the transport function structure. They comprise the public API.
+ LONGBOW_RUN_TEST_CASE(Global, rtaTransport_Close);
+ LONGBOW_RUN_TEST_CASE(Global, rtaTransport_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, rtaTransport_Open);
+ LONGBOW_RUN_TEST_CASE(Global, rtaTransport_PassCommand);
+
+ LONGBOW_RUN_TEST_CASE(Global, rtaTransport_Recv_OK);
+ LONGBOW_RUN_TEST_CASE(Global, rtaTransport_Recv_WouldBlock);
+
+ LONGBOW_RUN_TEST_CASE(Global, rtaTransport_Send_OK);
+ LONGBOW_RUN_TEST_CASE(Global, rtaTransport_Send_WouldBlock);
+
+// LONGBOW_RUN_TEST_CASE(Global, unrecoverable);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ _commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, rtaTransport_Close)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxTransportConfig *config = createSimpleConfig(data);
+
+ int api_fd = rtaTransport_Open(data->transport, config);
+
+ RtaConnection *conn = lookupRtaConnectionInsideFramework(data, api_fd, 1E+6);
+ assertNotNull(conn, "Could not find connection");
+
+ rtaTransport_Close(data->transport, api_fd);
+
+ // now wait until it's gone
+ bool gone = lookupNullRtaConnectionInsideFramework(data, api_fd, 1E+6);
+ assertTrue(gone, "Did not remove connection after 1 second timeout");
+
+ ccnxTransportConfig_Destroy(&config);
+}
+
+LONGBOW_TEST_CASE(Global, rtaTransport_Create_Destroy)
+{
+ RTATransport *transport = rtaTransport_Create();
+ assertNotNull(transport, "rtaTransport_Create() returns NULL");
+
+ rtaTransport_Destroy(&transport);
+ assertNull(transport, "rtaTransport_Destroy did not null paramter");
+}
+
+LONGBOW_TEST_CASE(Global, rtaTransport_Open)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxTransportConfig *config = createSimpleConfig(data);
+
+ int api_fd = rtaTransport_Open(data->transport, config);
+
+ RtaConnection *conn = lookupRtaConnectionInsideFramework(data, api_fd, 1E+6);
+ assertNotNull(conn, "Could not find connection");
+
+ ccnxTransportConfig_Destroy(&config);
+}
+
+/**
+ * PassCommand sends a user RTA Command over the command channel.
+ * This test will intercept the transport side of the command channel so
+ * we can easily verify the command went through.
+ */
+LONGBOW_TEST_CASE(Global, rtaTransport_PassCommand)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ PARCRingBuffer1x1 *previousRingBuffer = data->transport->commandRingBuffer;
+ PARCNotifier *previousNotifier = data->transport->commandNotifier;
+
+ PARCRingBuffer1x1 *testRingBuffer = parcRingBuffer1x1_Create(32, NULL);
+ PARCNotifier *testNotifier = parcNotifier_Create();
+
+
+ // Insert our new socket pair so we can intercept the commands
+ // No acquire here because we will be resetting them and destroying all in this scope
+ data->transport->commandRingBuffer = testRingBuffer;
+ data->transport->commandNotifier = testNotifier;
+
+ // Create a simple command to send
+ RtaCommand *command = rtaCommand_CreateShutdownFramework();
+ rtaTransport_PassCommand(data->transport, command);
+ rtaCommand_Release(&command);
+
+ RtaCommand *testCommand = rtaCommand_Read(testRingBuffer);
+ assertNotNull(testCommand, "Got null command from the ring buffer.");
+ assertTrue(rtaCommand_IsShutdownFramework(testCommand), "Command not a shutdown framework");
+
+ // All's well
+
+ rtaCommand_Release(&testCommand);
+
+ // now restore the sockets so things close up nicely
+ data->transport->commandRingBuffer = previousRingBuffer;
+ data->transport->commandNotifier = previousNotifier;
+
+ parcRingBuffer1x1_Release(&testRingBuffer);
+ parcNotifier_Release(&testNotifier);
+}
+
+LONGBOW_TEST_CASE(Global, rtaTransport_Recv_OK)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ int api_fd, transport_fd;
+
+ _RTASocketPair pair = _rtaTransport_CreateSocketPair(data->transport, 128 * 1024);
+ api_fd = pair.up;
+ transport_fd = pair.down;
+
+ // Set non-blocking flag
+ int flags = fcntl(api_fd, F_GETFL, NULL);
+ assertTrue(flags != -1, "fcntl failed to obtain file descriptor flags (%d)\n", errno);
+ int failure = fcntl(api_fd, F_SETFL, flags | O_NONBLOCK);
+ assertFalse(failure, "fcntl failed to set file descriptor flags (%d)\n", errno);
+
+ char *buffer = "born free, as free as the wind blows";
+ ssize_t nwritten = write(transport_fd, &buffer, sizeof(&buffer));
+ assertTrue(nwritten == sizeof(&buffer), "Wrong write size, expected %zu got %zd", sizeof(&buffer), nwritten);
+
+ CCNxMetaMessage *msg = NULL;
+ TransportIOStatus result = rtaTransport_Recv(data->transport, api_fd, &msg, CCNxStackTimeout_Never);
+ assertTrue(result != TransportIOStatus_Error, "Failed to read a good socket");
+ assertTrue((void *) msg == (void *) buffer, "Read wrong pointer, got %p expected %p", (void *) msg, (void *) buffer);
+
+ close(api_fd);
+ close(transport_fd);
+}
+
+LONGBOW_TEST_CASE(Global, rtaTransport_Recv_WouldBlock)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ int api_fd, transport_fd;
+
+ _RTASocketPair pair = _rtaTransport_CreateSocketPair(data->transport, 128 * 1024);
+ api_fd = pair.up;
+ transport_fd = pair.down;
+
+ // Set non-blocking flag
+ int flags = fcntl(api_fd, F_GETFL, NULL);
+ assertTrue(flags != -1, "fcntl failed to obtain file descriptor flags (%d)\n", errno);
+ int failure = fcntl(api_fd, F_SETFL, flags | O_NONBLOCK);
+ assertFalse(failure, "fcntl failed to set file descriptor flags (%d)\n", errno);
+
+ // Don't write anything
+
+ CCNxMetaMessage *msg = NULL;
+ TransportIOStatus result = rtaTransport_Recv(data->transport, api_fd, &msg, CCNxStackTimeout_Immediate);
+ assertTrue(result == TransportIOStatus_Timeout, "Should have returned failure due to blocking");
+
+ close(api_fd);
+ close(transport_fd);
+}
+
+
+/**
+ * This function will receive what the API Connector sends down the stack
+ */
+static void
+mockDowncallRead(PARCEventQueue *queue, PARCEventType type, void *stack)
+{
+ TransportMessage *tm = rtaComponent_GetMessage(queue);
+ assertNotNull(tm, "got null transport message");
+
+ CCNxTlvDictionary *dictionary = transportMessage_GetDictionary(tm);
+ CCNxCodecNetworkBufferIoVec *vec = ccnxWireFormatMessage_GetIoVec(dictionary);
+ const struct iovec *iov = ccnxCodecNetworkBufferIoVec_GetArray(vec);
+
+ // we encapsualted a pointer to this counter inside the wire format
+ unsigned *downcallReadCountPtr = iov[0].iov_base;
+ (*downcallReadCountPtr)++;
+
+ transportMessage_Destroy(&tm);
+}
+
+CCNxCodecNetworkBufferMemoryBlockFunctions memfunc = {
+ .allocator = NULL,
+ .deallocator = NULL
+};
+
+/**
+ * This test does not actually need to receive the message in TestingLower. It could have passed
+ * any socket pair to rtaTransport_Send and inspected the result immediately.
+ */
+LONGBOW_TEST_CASE(Global, rtaTransport_Send_OK)
+{
+ testing_null_ops.downcallRead = mockDowncallRead;
+
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxTransportConfig *config = createSimpleConfig(data);
+
+ unsigned downcallReadCount = 0;
+
+ CCNxCodecNetworkBuffer *netbuff = ccnxCodecNetworkBuffer_CreateFromArray(&memfunc, NULL, sizeof(downcallReadCount), (uint8_t *) &downcallReadCount);
+ CCNxCodecNetworkBufferIoVec *vec = ccnxCodecNetworkBuffer_CreateIoVec(netbuff);
+ CCNxTlvDictionary *wire = ccnxWireFormatMessage_FromInterestPacketTypeIoVec(CCNxTlvDictionary_SchemaVersion_V1, vec);
+
+ int api_fd = rtaTransport_Open(data->transport, config);
+
+ CCNxMetaMessage *msg = ccnxMetaMessage_Acquire(wire);
+ bool success = rtaTransport_Send(data->transport, api_fd, msg, CCNxStackTimeout_Never);
+ assertTrue(success, "Got error writing to api_fd %d\n", api_fd);
+ ccnxMetaMessage_Release(&msg);
+
+ // now spin on it
+ unsigned maxTries = 2000; // about 1 second
+ while ((downcallReadCount == 0) && (maxTries > 0)) {
+ maxTries--;
+ usleep(500);
+ }
+
+ printf("Read message after %d tries\n", 2000 - maxTries);
+
+ ccnxTlvDictionary_Release(&wire);
+ ccnxCodecNetworkBufferIoVec_Release(&vec);
+ ccnxCodecNetworkBuffer_Release(&netbuff);
+
+ ccnxTransportConfig_Destroy(&config);
+}
+
+/**
+ * Fill up the socket with junk, then make sure it would blocks
+ */
+LONGBOW_TEST_CASE(Global, rtaTransport_Send_WouldBlock)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ int api_fd, transport_fd;
+
+ _RTASocketPair pair = _rtaTransport_CreateSocketPair(data->transport, 128 * 1024);
+ api_fd = pair.up;
+ transport_fd = pair.down;
+
+ // Set non-blocking flag
+ int flags = fcntl(api_fd, F_GETFL, NULL);
+ assertTrue(flags != -1, "fcntl failed to obtain file descriptor flags (%d)\n", errno);
+ int failure = fcntl(api_fd, F_SETFL, flags | O_NONBLOCK);
+ assertFalse(failure, "fcntl failed to set file descriptor flags (%d)\n", errno);
+
+ // write junk until it would block
+ char buffer[1024];
+ while (write(api_fd, buffer, 1024) > 0) {
+ ;
+ }
+
+ assertTrue(errno == EWOULDBLOCK, "wrote until it would block, but got some other error: (%d) %s", errno, strerror(errno));
+
+ // now call the function to test and make sure it does the right thing
+ // if it would block
+ CCNxTlvDictionary *interest = trafficTools_CreateDictionaryInterest();
+ CCNxMetaMessage *msg = ccnxMetaMessage_CreateFromInterest(interest);
+
+ bool success = rtaTransport_Send(data->transport, api_fd, msg, CCNxStackTimeout_Immediate);
+ printf("success %d, errno %d expected %d\n", success, errno, EWOULDBLOCK);
+
+ assertFalse(success, "Send did not return a failure, even though it would have blocked");
+ assertTrue(errno == EWOULDBLOCK, "wrote until it would block, but got some other error: (%d) %s", errno, strerror(errno));
+
+ ccnxMetaMessage_Release(&msg);
+ ccnxTlvDictionary_Release(&interest);
+
+ close(api_fd);
+ close(transport_fd);
+}
+
+/**
+ * Pass it an invalid socket. This will cause a trap in the send code.
+ */
+LONGBOW_TEST_CASE_EXPECTS(Global, rtaTransport_Send_Error, .event = &LongBowTrapUnrecoverableState)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxTlvDictionary *interest = trafficTools_CreateDictionaryInterest();
+ data->msg = ccnxMetaMessage_Acquire(interest);
+ ccnxTlvDictionary_Release(&interest);
+
+ rtaTransport_Send(data->transport, 999, data->msg, CCNxStackTimeout_Immediate);
+}
+
+LONGBOW_TEST_CASE_EXPECTS(Global, unrecoverable, .event = &LongBowTrapUnrecoverableState)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxTlvDictionary *interest = trafficTools_CreateDictionaryInterest();
+ data->msg = ccnxMetaMessage_CreateFromInterest(interest);
+ ccnxTlvDictionary_Release(&interest);
+
+ rtaTransport_Send(NULL, 999, data->msg, CCNxStackTimeout_Immediate);
+
+ ccnxMetaMessage_Release(&(data->msg));
+}
+
+// ==================================================================================
+// Local
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, _rtaTransport_AddStack);
+ LONGBOW_RUN_TEST_CASE(Local, _rtaTransport_GetStack);
+ LONGBOW_RUN_TEST_CASE(Local, _rtaTransport_GetStack_Missing);
+
+ LONGBOW_RUN_TEST_CASE(Local, _rtaTransport_CreateSocketPair);
+ LONGBOW_RUN_TEST_CASE(Local, _rtaTransport_GetProtocolStackEntry_Exists);
+ LONGBOW_RUN_TEST_CASE(Local, _rtaTransport_GetProtocolStackEntry_NotExists);
+ LONGBOW_RUN_TEST_CASE(Local, _rtaTransport_AddProtocolStackEntry);
+ LONGBOW_RUN_TEST_CASE(Local, _rtaTransport_CreateConnection);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ longBowTestCase_SetClipBoardData(testCase, _commonSetup());
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ _commonTeardown(longBowTestCase_GetClipBoardData(testCase));
+
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDERR_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks memory by %d allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Local, _rtaTransport_CreateSocketPair)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ int a, b;
+
+ _RTASocketPair pair = _rtaTransport_CreateSocketPair(data->transport, 128 * 1024);
+ a = pair.up;
+ b = pair.down;
+ assertFalse(a < 0, "socket a is error: %d", a);
+ assertFalse(b < 0, "socket b is error: %d", b);
+
+ ssize_t nwritten = write(a, &a, sizeof(a));
+ assertTrue(nwritten == sizeof(a), "Wrong write size, expected %zu got %zd", sizeof(a), nwritten);
+
+ int test;
+ ssize_t nread = read(b, &test, sizeof(test));
+ assertTrue(nread == sizeof(test), "Wrong read size, expected %zu got %zd", sizeof(test), nread);
+
+ assertTrue(test == a, "read wrong value, got %d wrote %d", test, a);
+
+ close(a);
+ close(b);
+}
+
+
+LONGBOW_TEST_CASE(Local, _rtaTransport_GetProtocolStackEntry_Exists)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxTransportConfig *config = createSimpleConfig(data);
+
+// uint64_t hash = ccnxStackConfig_HashCode(ccnxTransportConfig_GetStackConfig(config));
+
+ _StackEntry *truth = _rtaTransport_AddStack(data->transport, ccnxTransportConfig_GetStackConfig(config));
+
+ _StackEntry *test = _rtaTransport_GetProtocolStackEntry(data->transport, config);
+
+ assertTrue(test == truth, "Wrong pointer, got %p expected %p", (void *) test, (void *) truth);
+
+ ccnxTransportConfig_Destroy(&config);
+}
+
+LONGBOW_TEST_CASE(Local, _rtaTransport_GetProtocolStackEntry_NotExists)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxTransportConfig *config = createSimpleConfig(data);
+
+ _rtaTransport_AddStack(data->transport, ccnxTransportConfig_GetStackConfig(config));
+
+ // Now create the missing one to lookup
+ // this one will have 2x api connectors listed
+ CCNxStackConfig *missingStackConfig =
+ apiConnector_ProtocolStackConfig(apiConnector_ProtocolStackConfig(ccnxStackConfig_Create()));
+ CCNxConnectionConfig *missingConnConfig = apiConnector_ConnectionConfig(ccnxConnectionConfig_Create());
+
+ CCNxTransportConfig *missingConfig = ccnxTransportConfig_Create(missingStackConfig, missingConnConfig);
+ ccnxStackConfig_Release(&missingStackConfig);
+
+ _StackEntry *test = _rtaTransport_GetProtocolStackEntry(data->transport, missingConfig);
+
+ assertNull(test, "Wrong pointer, got %p expected %p", (void *) test, (void *) NULL);
+ ccnxTransportConfig_Destroy(&missingConfig);
+ ccnxTransportConfig_Destroy(&config);
+}
+
+LONGBOW_TEST_CASE(Local, _rtaTransport_AddProtocolStackEntry)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxTransportConfig *config = createSimpleConfig(data);
+
+ _StackEntry *entry = _rtaTransport_AddProtocolStackEntry(data->transport, config);
+ assertNotNull(entry, "Got null entry from _rtaTransport_AddProtocolStackEntry");
+
+ ccnxTransportConfig_Destroy(&config);
+}
+
+LONGBOW_TEST_CASE(Local, _rtaTransport_CreateConnection)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxTransportConfig *config = createSimpleConfig(data);
+
+ _StackEntry *entry = _rtaTransport_AddProtocolStackEntry(data->transport, config);
+
+ _RTASocketPair pair = _rtaTransport_CreateSocketPair(data->transport, 128 * 1024);
+
+ _rtaTransport_CreateConnection(data->transport, config, entry, pair);
+
+ // wait up to 1 second
+ RtaConnection *conn = lookupRtaConnectionInsideFramework(data, pair.up, 1E+6);
+ assertNotNull(conn, "Could not find connection in connection table, timeout at %.6f seconds", 1.0);
+
+ ccnxTransportConfig_Destroy(&config);
+}
+
+LONGBOW_TEST_CASE(Local, _rtaTransport_AddStack)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+ CCNxStackConfig *stackConfig = ccnxStackConfig_Create();
+ _StackEntry *entry = _rtaTransport_AddStack(data->transport, stackConfig);
+
+ uint64_t hash = ccnxStackConfig_HashCode(stackConfig);
+ _StackEntry *test = _rtaTransport_GetStack(data->transport, hash);
+ assertTrue(test == entry, "Wrong pointer, got %p expected %p", (void *) test, (void *) entry);
+
+ ccnxStackConfig_Release(&stackConfig);
+}
+
+LONGBOW_TEST_CASE(Local, _rtaTransport_GetStack)
+{
+ struct test_vector {
+ uint64_t hash;
+ int stackid;
+ _StackEntry *entry;
+ } vector[] = {
+ { .hash = 20, .stackid = 30, .entry = NULL },
+ { .hash = 10, .stackid = 77, .entry = NULL },
+ { .hash = 990, .stackid = 31, .entry = NULL },
+ { .hash = 0, .stackid = 0, .entry = NULL },
+ };
+
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxStackConfig *stackConfig = ccnxStackConfig_Create();
+
+ char key[10];
+ for (int i = 0; vector[i].hash != 0; i++) {
+ sprintf(key, "key%d", i);
+ PARCJSONValue *json = parcJSONValue_CreateFromNULL();
+ ccnxStackConfig_Add(stackConfig, key, json);
+ parcJSONValue_Release(&json);
+ vector[i].hash = ccnxStackConfig_HashCode(stackConfig);
+ vector[i].entry = _rtaTransport_AddStack(data->transport, stackConfig);
+ }
+ ccnxStackConfig_Release(&stackConfig);
+
+ // now look them up
+ for (int i = 0; vector[i].hash != 0; i++) {
+ _StackEntry *test = _rtaTransport_GetStack(data->transport, vector[i].hash);
+ assertTrue(test == vector[i].entry, "Wrong pointer, got %p expected %p", (void *) test, (void *) vector[i].entry);
+ }
+}
+
+LONGBOW_TEST_CASE(Local, _rtaTransport_GetStack_Missing)
+{
+ TestData *data = longBowTestCase_GetClipBoardData(testCase);
+
+ CCNxStackConfig *stackConfig = ccnxStackConfig_Create();
+ _rtaTransport_AddStack(data->transport, stackConfig);
+
+ PARCJSONValue *json = parcJSONValue_CreateFromNULL();
+ ccnxStackConfig_Add(stackConfig, "someKey", json);
+ parcJSONValue_Release(&json);
+
+ _StackEntry *test = _rtaTransport_GetStack(data->transport, ccnxStackConfig_HashCode(stackConfig));
+
+ ccnxStackConfig_Release(&stackConfig);
+ assertNull(test, "Wrong pointer, got %p expected %p", (void *) test, NULL);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(rta_Transport);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}