aboutsummaryrefslogtreecommitdiffstats
path: root/metis/ccnx/forwarder/metis/processor/test
diff options
context:
space:
mode:
Diffstat (limited to 'metis/ccnx/forwarder/metis/processor/test')
-rw-r--r--metis/ccnx/forwarder/metis/processor/test/CMakeLists.txt21
-rw-r--r--metis/ccnx/forwarder/metis/processor/test/test_metis_ContentStore.c437
-rw-r--r--metis/ccnx/forwarder/metis/processor/test/test_metis_FIB.c549
-rw-r--r--metis/ccnx/forwarder/metis/processor/test/test_metis_FibEntry.c136
-rw-r--r--metis/ccnx/forwarder/metis/processor/test/test_metis_FibEntryList.c115
-rw-r--r--metis/ccnx/forwarder/metis/processor/test/test_metis_HashTableFunction.c133
-rw-r--r--metis/ccnx/forwarder/metis/processor/test/test_metis_MatchingRulesTable.c666
-rw-r--r--metis/ccnx/forwarder/metis/processor/test/test_metis_MessageProcessor.c1533
-rw-r--r--metis/ccnx/forwarder/metis/processor/test/test_metis_PIT.c223
-rw-r--r--metis/ccnx/forwarder/metis/processor/test/test_metis_PitEntry.c294
-rw-r--r--metis/ccnx/forwarder/metis/processor/test/test_metis_StandardPIT.c498
-rw-r--r--metis/ccnx/forwarder/metis/processor/test/testrig_MockTap.h104
12 files changed, 4709 insertions, 0 deletions
diff --git a/metis/ccnx/forwarder/metis/processor/test/CMakeLists.txt b/metis/ccnx/forwarder/metis/processor/test/CMakeLists.txt
new file mode 100644
index 00000000..aae53353
--- /dev/null
+++ b/metis/ccnx/forwarder/metis/processor/test/CMakeLists.txt
@@ -0,0 +1,21 @@
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+set(TestsExpectedToPass
+ test_metis_FIB
+ test_metis_FibEntryList
+ test_metis_HashTableFunction
+ test_metis_FibEntry
+ test_metis_MatchingRulesTable
+ test_metis_MessageProcessor
+ test_metis_PIT
+ test_metis_PitEntry
+ test_metis_StandardPIT
+)
+
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
+
diff --git a/metis/ccnx/forwarder/metis/processor/test/test_metis_ContentStore.c b/metis/ccnx/forwarder/metis/processor/test/test_metis_ContentStore.c
new file mode 100644
index 00000000..65c2db74
--- /dev/null
+++ b/metis/ccnx/forwarder/metis/processor/test/test_metis_ContentStore.c
@@ -0,0 +1,437 @@
+/*
+ * 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_ContentStore.c"
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.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_ContentStore)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ 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_ContentStore)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(metis_ContentStore)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ============================================================================
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, metisContentStore_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, metisContentStore_Create_ZeroCapacity);
+
+ LONGBOW_RUN_TEST_CASE(Global, metisContentStore_Fetch_ByName);
+ LONGBOW_RUN_TEST_CASE(Global, metisContentStore_Fetch_ByNameAndKeyId);
+ LONGBOW_RUN_TEST_CASE(Global, metisContentStore_Fetch_ByNameAndObjectHash);
+
+ LONGBOW_RUN_TEST_CASE(Global, metisContentStore_Fetch_Lru);
+
+ LONGBOW_RUN_TEST_CASE(Global, metisContentStore_Save_ZeroCapacity);
+ LONGBOW_RUN_TEST_CASE(Global, metisContentStore_Save_CapacityLimit);
+ LONGBOW_RUN_TEST_CASE(Global, metisContentStore_Save_WithoutEviction);
+ LONGBOW_RUN_TEST_CASE(Global, metisContentStore_Save_WithEviction);
+
+ LONGBOW_RUN_TEST_CASE(Global, metisContentStore_Save_DuplicateHash);
+}
+
+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, metisContentStore_Create_Destroy)
+{
+ size_t objectCapacity = 10;
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+ MetisContentStore *store = metisContentStore_Create(objectCapacity, logger);
+ metisLogger_Release(&logger);
+
+ assertTrue(store->objectCapacity == objectCapacity, "Wrong capacity, expected %zu got %zu", objectCapacity, store->objectCapacity);
+ assertTrue(store->objectCount == 0, "Wrong initial count, expected %u got %zu", 0, store->objectCount);
+ metisContentStore_Destroy(&store);
+
+ assertTrue(parcSafeMemory_ReportAllocation(STDOUT_FILENO) == 0, "Memory imbalance after create/destroy, expected %u got %u", 0, parcMemory_Outstanding());
+}
+
+LONGBOW_TEST_CASE(Global, metisContentStore_Create_ZeroCapacity)
+{
+ size_t objectCapacity = 0;
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+ MetisContentStore *store = metisContentStore_Create(objectCapacity, logger);
+ assertTrue(store->objectCapacity == objectCapacity, "Wrong capacity, expected %zu got %zu", objectCapacity, store->objectCapacity);
+ assertTrue(store->objectCount == 0, "Wrong initial count, expected %u got %zu", 0, store->objectCount);
+ metisLogger_Release(&logger);
+ metisContentStore_Destroy(&store);
+}
+
+LONGBOW_TEST_CASE(Global, metisContentStore_Fetch_ByName)
+{
+ size_t objectCapacity = 10;
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+ MetisContentStore *store = metisContentStore_Create(objectCapacity, logger);
+ MetisMessage *object_1 = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 2, logger);
+ MetisMessage *object_2 = metisMessage_CreateFromArray(metisTestDataV0_SecondObject, sizeof(metisTestDataV0_SecondObject), 1, 2, logger);
+
+ metisContentStore_Save(store, object_1);
+ metisContentStore_Save(store, object_2);
+
+ MetisMessage *interestByName = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 3, 5, logger);
+ MetisMessage *testObject = metisContentStore_Fetch(store, interestByName);
+ assertNotNull(testObject, "Fetch did not find match when it should have");
+
+ // two objects with same name, 1st one will win
+ assertTrue(testObject == object_1, "Fetch returned wrong object, expecting %p got %p", (void *) object_1, (void *) testObject);
+
+ metisLogger_Release(&logger);
+ metisContentStore_Destroy(&store);
+ metisMessage_Release(&object_1);
+ metisMessage_Release(&object_2);
+ metisMessage_Release(&testObject);
+ metisMessage_Release(&interestByName);
+}
+
+LONGBOW_TEST_CASE(Global, metisContentStore_Fetch_ByNameAndKeyId)
+{
+ size_t objectCapacity = 10;
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+ MetisContentStore *store = metisContentStore_Create(objectCapacity, logger);
+ MetisMessage *object_1 = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 2, logger);
+ MetisMessage *object_2 = metisMessage_CreateFromArray(metisTestDataV0_SecondObject, sizeof(metisTestDataV0_SecondObject), 1, 2, logger);
+
+ metisContentStore_Save(store, object_1);
+ metisContentStore_Save(store, object_2);
+
+ MetisMessage *interestByNameKeyId = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName_keyid, sizeof(metisTestDataV0_InterestWithName_keyid), 3, 5, logger);
+ MetisMessage *testObject = metisContentStore_Fetch(store, interestByNameKeyId);
+ assertNotNull(testObject, "Fetch did not find match when it should have");
+
+ // two objects with same name, 1st one will win
+ assertTrue(testObject == object_1, "Fetch returned wrong object, expecting %p got %p", (void *) object_1, (void *) testObject);
+
+ metisLogger_Release(&logger);
+ metisContentStore_Destroy(&store);
+ metisMessage_Release(&object_1);
+ metisMessage_Release(&object_2);
+ metisMessage_Release(&testObject);
+ metisMessage_Release(&interestByNameKeyId);
+}
+
+LONGBOW_TEST_CASE(Global, metisContentStore_Fetch_ByNameAndObjectHash)
+{
+ size_t objectCapacity = 10;
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+ MetisContentStore *store = metisContentStore_Create(objectCapacity, logger);
+ MetisMessage *object_1 = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 2, logger);
+ MetisMessage *object_2 = metisMessage_CreateFromArray(metisTestDataV0_SecondObject, sizeof(metisTestDataV0_SecondObject), 1, 2, logger);
+
+ metisContentStore_Save(store, object_1);
+ metisContentStore_Save(store, object_2);
+
+ MetisMessage *interestByNameObjectHash = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName_objecthash, sizeof(metisTestDataV0_InterestWithName_objecthash), 3, 5, logger);
+
+ // this should retrieve object_1 because that is the one whose
+ // content object hash matches the interest
+ MetisMessage *testObject = metisContentStore_Fetch(store, interestByNameObjectHash);
+ assertNotNull(testObject, "Fetch did not find match when it should have");
+
+ // two objects with same name, 1st one will win
+ assertTrue(testObject == object_1, "Fetch returned wrong object, expecting %p got %p", (void *) object_1, (void *) testObject);
+
+ metisLogger_Release(&logger);
+ metisContentStore_Destroy(&store);
+ metisMessage_Release(&object_1);
+ metisMessage_Release(&object_2);
+ metisMessage_Release(&testObject);
+ metisMessage_Release(&interestByNameObjectHash);
+}
+
+/*
+ * Create an cache and access objects to make sure the LRU is evicting the right way
+ */
+LONGBOW_TEST_CASE(Global, metisContentStore_Fetch_Lru)
+{
+ const size_t objectCapacity = 2;
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ parcLogReporter_Release(&reporter);
+
+ MetisContentStore *store = metisContentStore_Create(objectCapacity, logger);
+
+ MetisMessage *object1 = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 2, logger);
+ MetisMessage *object2 = metisMessage_CreateFromArray(metisTestDataV0_object_with_othername, sizeof(metisTestDataV0_object_with_othername), 2, 2, logger);
+
+ metisContentStore_Save(store, object1);
+ metisContentStore_Save(store, object2);
+
+ // object 2 sould be at top of LRU (was saved last). Fetch object 1, then evict object 2.
+
+ // interest_with_name will match the name in object1.
+ MetisMessage *interestByName = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 3, 5, logger);
+ MetisMessage *testObject = metisContentStore_Fetch(store, interestByName);
+
+ assertTrue(testObject == object1, "Fetch returned wrong object, expecting %p got %p", (void *) object1, (void *) testObject);
+
+ // objectcapacity = 2, so object 3 will evict bottom of LRU
+ MetisMessage *object3 = metisMessage_CreateFromArray(metisTestDataV0_SecondObject, sizeof(metisTestDataV0_SecondObject), 4, 2, logger);
+ metisContentStore_Save(store, object3);
+
+ // object 2 should be evicted
+ MetisMessage *interestOtherName = metisMessage_CreateFromArray(metisTestDataV0_InterestWithOtherName, sizeof(metisTestDataV0_InterestWithOtherName), 5, 5, logger);
+ MetisMessage *testEvictedObject = metisContentStore_Fetch(store, interestOtherName);
+ assertNull(testEvictedObject, "object with othername should have been evicted");
+
+ // as final sanity check, make sure object 1 is still in the list
+ MetisMessage *testObject1Again = metisContentStore_Fetch(store, interestByName);
+ assertNotNull(testObject1Again, "Did not retrieve object1 from the content store");
+
+ metisLogger_Release(&logger);
+ metisContentStore_Destroy(&store);
+ metisMessage_Release(&testObject1Again);
+ metisMessage_Release(&object1);
+ metisMessage_Release(&object2);
+ metisMessage_Release(&object3);
+ metisMessage_Release(&testObject);
+ metisMessage_Release(&interestByName);
+ metisMessage_Release(&interestOtherName);
+}
+
+
+LONGBOW_TEST_CASE(Global, metisContentStore_Save_WithoutEviction)
+{
+ size_t objectCapacity = 10;
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+ MetisContentStore *store = metisContentStore_Create(objectCapacity, logger);
+ MetisMessage *object_1 = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 2, logger);
+ MetisMessage *object_2 = metisMessage_CreateFromArray(metisTestDataV0_SecondObject, sizeof(metisTestDataV0_SecondObject), 1, 2, logger);
+
+ metisContentStore_Save(store, object_1);
+ metisContentStore_Save(store, object_2);
+
+ assertTrue(store->stats.countAdds == 2, "Wrong countAdds, expected %u got %" PRIu64, 2, store->stats.countAdds);
+ assertTrue(store->stats.countLruEvictions == 0, "Wrong countLruEvictions, expected %u got %" PRIu64, 0, store->stats.countLruEvictions);
+ assertTrue(metisLruList_Length(store->lruList) == 2, "Wrong metisLruList_Length, expected %u got %zu", 2, metisLruList_Length(store->lruList));
+
+ metisLogger_Release(&logger);
+ metisContentStore_Destroy(&store);
+ metisMessage_Release(&object_1);
+ metisMessage_Release(&object_2);
+}
+
+LONGBOW_TEST_CASE(Global, metisContentStore_Save_WithEviction)
+{
+ size_t objectCapacity = 1;
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+ MetisContentStore *store = metisContentStore_Create(objectCapacity, logger);
+ MetisMessage *object_1 = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 2, logger);
+ MetisMessage *object_2 = metisMessage_CreateFromArray(metisTestDataV0_SecondObject, sizeof(metisTestDataV0_SecondObject), 1, 2, logger);
+
+ metisContentStore_Save(store, object_1);
+
+ assertTrue(store->objectCount == 1, "Wrong objectCount. Expected %u, got %zu", 1, store->objectCount);
+
+ metisContentStore_Save(store, object_2);
+
+ // Capacity is 1, so we should never grow bigger than that.
+ assertTrue(store->objectCount == 1, "Wrong objectCount. Expected %u, got %zu", 1, store->objectCount);
+
+ assertTrue(store->stats.countAdds == 2, "Wrong countAdds, expected %u got %" PRIu64, 2, store->stats.countAdds);
+ assertTrue(store->stats.countLruEvictions == 1, "Wrong countLruEvictions, expected %u got %" PRIu64, 1, store->stats.countLruEvictions);
+ assertTrue(metisLruList_Length(store->lruList) == 1, "Wrong metisLruList_Length, expected %u got %zu", 1, metisLruList_Length(store->lruList));
+
+ metisLogger_Release(&logger);
+ metisContentStore_Destroy(&store);
+ metisMessage_Release(&object_1);
+ metisMessage_Release(&object_2);
+}
+
+LONGBOW_TEST_CASE(Global, metisContentStore_Save_ZeroCapacity)
+{
+ size_t objectCapacity = 0;
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+ MetisContentStore *store = metisContentStore_Create(objectCapacity, logger);
+
+ MetisMessage *object_1 = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 2, logger);
+ bool success = metisContentStore_Save(store, object_1);
+ assertFalse(success, "Should have returned failure with 0 capacity object store saving something");
+
+ metisLogger_Release(&logger);
+ metisMessage_Release(&object_1);
+ metisContentStore_Destroy(&store);
+}
+
+static MetisMessage *
+_createUniqueMetisMessage(int tweakNumber, uint8_t *template, size_t templateSize, int nameOffset)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+ PARCBuffer *buffer = parcBuffer_Allocate(templateSize);
+ memcpy(parcBuffer_Overlay(buffer, 0), template, templateSize); // Copy the template to new memory
+
+ // Tweak the encoded object's name so the name hash varies each time.
+ uint8_t *bufPtr = parcBuffer_Overlay(buffer, 0);
+ bufPtr[nameOffset] = 'a' + tweakNumber;
+
+ MetisMessage *result = metisMessage_CreateFromArray(bufPtr, templateSize, 1, 2, logger);
+ metisLogger_Release(&logger);
+ parcBuffer_Release(&buffer);
+
+ return result;
+}
+
+LONGBOW_TEST_CASE(Global, metisContentStore_Save_CapacityLimit)
+{
+ size_t storeCapacity = 5;
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+ MetisContentStore *store = metisContentStore_Create(storeCapacity, logger);
+
+ for (int i = 1; i < storeCapacity * 2; i++) {
+
+ int offsetOfNameInEncodedObject = metisTestDataV0_EncodedObject.offset + 4;
+ MetisMessage *object = _createUniqueMetisMessage(i, metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), offsetOfNameInEncodedObject);
+
+ bool success = metisContentStore_Save(store, object);
+
+ assertTrue(success, "Unexpectedly failed to add entry to ContentStore");
+
+ if (i < store->objectCapacity) {
+ assertTrue(store->objectCount == i, "Unexpected value for store->objectCount");
+ } else {
+ assertTrue(store->objectCount == store->objectCapacity, "Unexpected value (%zu) for store->objectCount (%zu)",
+ store->objectCount, store->objectCapacity);
+ }
+
+ if (success) {
+ metisMessage_Release(&object);
+ }
+ }
+ metisLogger_Release(&logger);
+ metisContentStore_Destroy(&store);
+}
+
+LONGBOW_TEST_CASE(Global, metisContentStore_Save_DuplicateHash)
+{
+ size_t storeCapacity = 5;
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+ MetisContentStore *store = metisContentStore_Create(storeCapacity, logger);
+
+ MetisMessage *object_1 = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 2, logger);
+
+ bool success = metisContentStore_Save(store, object_1);
+
+ for (int i = 0; i < 10; i++) {
+ MetisMessage *object_1_dup = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 2, logger);
+
+ success = metisContentStore_Save(store, object_1_dup);
+
+ assertFalse(success, "Unexpectedly added duplicated entry to ContentStore");
+
+ assertTrue(store->objectCount == 1, "ObjectCount should be 1");
+
+ metisMessage_Release(&object_1_dup);
+ }
+
+ metisLogger_Release(&logger);
+ metisMessage_Release(&object_1);
+ metisContentStore_Destroy(&store);
+}
+
+// ============================================================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, hashTableFunction_ContentStoreEntryDestroyer);
+}
+
+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, hashTableFunction_ContentStoreEntryDestroyer)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+// ============================================================================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metis_ContentStore);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/metis/ccnx/forwarder/metis/processor/test/test_metis_FIB.c b/metis/ccnx/forwarder/metis/processor/test/test_metis_FIB.c
new file mode 100644
index 00000000..0d02501f
--- /dev/null
+++ b/metis/ccnx/forwarder/metis/processor/test/test_metis_FIB.c
@@ -0,0 +1,549 @@
+/*
+ * 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_FIB.c"
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/logging/parc_LogReporterTextStdout.h>
+
+#include <ccnx/forwarder/metis/testdata/metis_TestDataV0.h>
+
+LONGBOW_TEST_RUNNER(metis_FIB)
+{
+ // 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_FIB)
+{
+ 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_FIB)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, metisFib_AddOrUpdate_Add);
+ LONGBOW_RUN_TEST_CASE(Global, metisFib_AddOrUpdate_Update);
+ LONGBOW_RUN_TEST_CASE(Global, metisFib_Create_Destroy);
+
+ LONGBOW_RUN_TEST_CASE(Global, metisFib_Match_Exists);
+ LONGBOW_RUN_TEST_CASE(Global, metisFib_Match_NotExists);
+ LONGBOW_RUN_TEST_CASE(Global, metisFib_Match_ExcludeIngress);
+
+ LONGBOW_RUN_TEST_CASE(Global, metisFib_Remove_NoEntry);
+ LONGBOW_RUN_TEST_CASE(Global, metisFib_Remove_ExistsNotLast);
+ LONGBOW_RUN_TEST_CASE(Global, metisFib_Remove_ExistsIsLast);
+
+ LONGBOW_RUN_TEST_CASE(Global, metisFIB_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, metisFib_AddOrUpdate_Add)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+ MetisFIB *fib = metisFIB_Create(logger);
+ metisLogger_Release(&logger);
+
+ CCNxName *ccnxName = ccnxName_CreateFromCString("lci:/foo/bar");
+ MetisTlvName *tlvName = metisTlvName_CreateFromCCNxName(ccnxName);
+ unsigned interfaceIndex = 22;
+ CPIAddress *nexthop = NULL;
+ struct timeval *lifetime = NULL;
+ unsigned cost = 12;
+
+ CPIRouteEntry *route = cpiRouteEntry_Create(ccnxName, interfaceIndex, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, lifetime, cost);
+
+ metisFIB_AddOrUpdate(fib, route, "random");
+ size_t hashCodeTableLength = parcHashCodeTable_Length(fib->tableByName);
+
+ MetisFibEntry *fibEntry = parcHashCodeTable_Get(fib->tableByName, tlvName);
+ size_t nexthopCount = metisFibEntry_NexthopCount(fibEntry);
+
+ cpiRouteEntry_Destroy(&route);
+ metisTlvName_Release(&tlvName);
+ metisFIB_Destroy(&fib);
+
+ assertTrue(hashCodeTableLength == 1, "Wrong hash table length, expected %u got %zu", 1, hashCodeTableLength);
+ assertTrue(nexthopCount == 1, "Wrong hash table length, expected %u got %zu", 1, nexthopCount);
+}
+
+LONGBOW_TEST_CASE(Global, metisFib_AddOrUpdate_Update)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+ MetisFIB *fib = metisFIB_Create(logger);
+ metisLogger_Release(&logger);
+
+ CCNxName *ccnxName = ccnxName_CreateFromCString("lci:/foo/bar");
+ MetisTlvName *tlvName = metisTlvName_CreateFromCCNxName(ccnxName);
+ unsigned interfaceIndex_1 = 22;
+ CPIAddress *nexthop = NULL;
+ struct timeval *lifetime = NULL;
+ unsigned cost = 12;
+
+ // ----- Add
+ CPIRouteEntry *route_1 = cpiRouteEntry_Create(ccnxName_Copy(ccnxName), interfaceIndex_1, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, lifetime, cost);
+ metisFIB_AddOrUpdate(fib, route_1, "random");
+
+ // ----- Update
+ unsigned interfaceIndex_2 = 33;
+ CPIRouteEntry *route_2 = cpiRouteEntry_Create(ccnxName_Copy(ccnxName), interfaceIndex_2, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, lifetime, cost);
+ metisFIB_AddOrUpdate(fib, route_2, "random");
+
+ // ----- Measure
+ size_t hashCodeTableLength = parcHashCodeTable_Length(fib->tableByName);
+ MetisFibEntry *fibEntry = parcHashCodeTable_Get(fib->tableByName, tlvName);
+ size_t nexthopCount = metisFibEntry_NexthopCount(fibEntry);
+
+
+ cpiRouteEntry_Destroy(&route_1);
+ cpiRouteEntry_Destroy(&route_2);
+ ccnxName_Release(&ccnxName);
+ metisTlvName_Release(&tlvName);
+ metisFIB_Destroy(&fib);
+
+ assertTrue(hashCodeTableLength == 1, "Wrong hash table length, expected %u got %zu", 1, hashCodeTableLength);
+ assertTrue(nexthopCount == 2, "Wrong hash table length, expected %u got %zu", 2, nexthopCount);
+}
+
+LONGBOW_TEST_CASE(Global, metisFib_Create_Destroy)
+{
+ size_t beforeMemory = parcMemory_Outstanding();
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+ MetisFIB *fib = metisFIB_Create(logger);
+ metisLogger_Release(&logger);
+
+ metisFIB_Destroy(&fib);
+ size_t afterMemory = parcMemory_Outstanding();
+
+ assertTrue(beforeMemory == afterMemory, "Memory imbalance on create/destroy: expected %zu got %zu", beforeMemory, afterMemory);
+}
+
+/**
+ * Add /hello/ouch and lookup that name
+ */
+LONGBOW_TEST_CASE(Global, metisFib_Match_Exists)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+ MetisFIB *fib = metisFIB_Create(logger);
+ CCNxName *ccnxNameToAdd = ccnxName_CreateFromCString("lci:/2=hello/0xF000=ouch");
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 2, logger);
+ metisLogger_Release(&logger);
+
+ unsigned interfaceIndex_1 = 22;
+ CPIAddress *nexthop = NULL;
+ struct timeval *lifetime = NULL;
+ unsigned cost = 12;
+
+ // ----- Add
+ CPIRouteEntry *routeAdd = cpiRouteEntry_Create(ccnxNameToAdd, interfaceIndex_1, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, lifetime, cost);
+ metisFIB_AddOrUpdate(fib, routeAdd, "random");
+
+ // ----- Match
+ MetisFibEntry *entry = metisFIB_Match(fib, interest);
+
+ // ----- Measure
+ size_t nexthopsLength = metisNumberSet_Length(metisFibEntry_GetNexthops(entry));
+
+ // ----- Cleanup
+ cpiRouteEntry_Destroy(&routeAdd);
+ metisMessage_Release(&interest);
+ metisFIB_Destroy(&fib);
+
+ // ----- Validate
+ assertTrue(nexthopsLength == 1, "Wrong nexthops length, expected %u got %zu", 1, nexthopsLength);
+}
+
+/**
+ * Add /foo/bar to connection 10
+ * Add /foo to connection 11
+ * Forward an Interest /foo/bar/cat from connection 10. Should select 11.
+ */
+LONGBOW_TEST_CASE(Global, metisFib_Match_ExcludeIngress)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+ MetisFIB *fib = metisFIB_Create(logger);
+
+ CCNxName *nameFoo = ccnxName_CreateFromCString("lci:/foo");
+ CCNxName *nameFooBar = ccnxName_CreateFromCString("lci:/foo/bar");
+
+ uint8_t encodedInterest[] = {
+ 0x01, 0x00, 0x00, 37, // ver = 1, type = interest, length = 37
+ 0xFF, 0x00, 0x00, 8, // hoplimit = 255, header length = 8
+ // ------------------------
+ 0x00, 0x01, 0x00, 25, // type = interest, length = 25
+ // ------------------------
+ 0x00, 0x00, 0x00, 21, // type = name, length = 21
+ 0x00, 0x01, 0x00, 3, // type = name, length = 3
+ 'f', 'o', 'o',
+ 0x00, 0x01, 0x00, 3, // type = name, length = 3
+ 'b', 'a', 'r',
+ 0x00, 0x01, 0x00, 3, // type = name, length = 3
+ 'c', 'a', 't',
+ };
+
+ MetisMessage *interest = metisMessage_CreateFromArray(encodedInterest, sizeof(encodedInterest), 10, 2, logger);
+ metisLogger_Release(&logger);
+
+ CPIAddress *nexthop = NULL;
+ struct timeval *lifetime = NULL;
+ unsigned cost = 12;
+
+ CPIRouteEntry *routeAdd;
+
+ // ----- Add long route to Interface 10
+ routeAdd = cpiRouteEntry_Create(nameFooBar, 10, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, lifetime, cost);
+ metisFIB_AddOrUpdate(fib, routeAdd, "random");
+ cpiRouteEntry_Destroy(&routeAdd);
+
+ // ----- Add short route to Interface 11
+ routeAdd = cpiRouteEntry_Create(nameFoo, 11, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, lifetime, cost);
+ metisFIB_AddOrUpdate(fib, routeAdd, "random");
+ cpiRouteEntry_Destroy(&routeAdd);
+
+ // ----- Match
+ MetisFibEntry *entry = metisFIB_Match(fib, interest);
+
+ // ----- Measure
+ size_t nexthopsLength = metisNumberSet_Length(metisFibEntry_GetNexthops(entry));
+
+ // ----- Validate
+ assertTrue(nexthopsLength == 1, "Wrong nexthops length, expected %u got %zu", 1, nexthopsLength);
+ bool hasEgress = metisNumberSet_Contains(metisFibEntry_GetNexthops(entry), 11);
+ assertTrue(hasEgress, "Egress interface 11 not in nexthop set");
+
+ // ----- Cleanup
+ metisMessage_Release(&interest);
+ metisFIB_Destroy(&fib);
+}
+
+
+/**
+ * Add /hello/ouch and lookup /party/ouch
+ */
+LONGBOW_TEST_CASE(Global, metisFib_Match_NotExists)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+ MetisFIB *fib = metisFIB_Create(logger);
+ CCNxName *ccnxNameToAdd = ccnxName_CreateFromCString("lci:/2=hello/0xF000=ouch");
+
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithOtherName, sizeof(metisTestDataV0_InterestWithOtherName), 1, 2, logger);
+ metisLogger_Release(&logger);
+
+ unsigned interfaceIndex_1 = 22;
+ CPIAddress *nexthop = NULL;
+ struct timeval *lifetime = NULL;
+ unsigned cost = 12;
+
+ // ----- Add
+ CPIRouteEntry *routeAdd = cpiRouteEntry_Create(ccnxNameToAdd, interfaceIndex_1, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, lifetime, cost);
+ metisFIB_AddOrUpdate(fib, routeAdd, "random");
+
+ // ----- Match
+ MetisFibEntry *entry = metisFIB_Match(fib, interest);
+
+ // ----- Measure
+ assertTrue(entry == NULL, "expected null");
+ cpiRouteEntry_Destroy(&routeAdd);
+ metisMessage_Release(&interest);
+ metisFIB_Destroy(&fib);
+
+ //size_t nexthopsLength = metisNumberSet_Length(metisFibEntry_GetNexthops(entry));
+
+ // ----- Cleanup
+ //cpiRouteEntry_Destroy(&routeAdd);
+ //metisMessage_Release(&interest);
+ //metisFibEntry_Release(&entry);
+ //metisFIB_Destroy(&fib);
+
+ // ----- Validate
+ //assertTrue(nexthopsLength == 0, "Wrong nexthops length, expected %u got %zu", 0, nexthopsLength);
+}
+
+/**
+ * Add /foo/bar and try to remove /baz
+ */
+LONGBOW_TEST_CASE(Global, metisFib_Remove_NoEntry)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+ MetisFIB *fib = metisFIB_Create(logger);
+ metisLogger_Release(&logger);
+
+ CCNxName *ccnxNameToAdd = ccnxName_CreateFromCString("lci:/foo/bar");
+ CCNxName *ccnxNameToRemove = ccnxName_CreateFromCString("lci:/baz");
+ MetisTlvName *tlvNameToCheck = metisTlvName_CreateFromCCNxName(ccnxNameToAdd);
+ unsigned interfaceIndex_1 = 22;
+ CPIAddress *nexthop = NULL;
+ struct timeval *lifetime = NULL;
+ unsigned cost = 12;
+
+ // ----- Add
+ CPIRouteEntry *routeAdd = cpiRouteEntry_Create(ccnxNameToAdd, interfaceIndex_1, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, lifetime, cost);
+ metisFIB_AddOrUpdate(fib, routeAdd, "random");
+
+ // ----- Remove
+ CPIRouteEntry *routeRemove = cpiRouteEntry_Create(ccnxNameToRemove, interfaceIndex_1, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, lifetime, cost);
+ metisFIB_Remove(fib, routeRemove);
+
+ // ----- Measure
+ size_t hashCodeTableLength = parcHashCodeTable_Length(fib->tableByName);
+ MetisFibEntry *fibEntry = parcHashCodeTable_Get(fib->tableByName, tlvNameToCheck);
+ size_t nexthopCount = metisFibEntry_NexthopCount(fibEntry);
+
+ // ----- Cleanup
+ cpiRouteEntry_Destroy(&routeAdd);
+ cpiRouteEntry_Destroy(&routeRemove);
+ metisTlvName_Release(&tlvNameToCheck);
+ metisFIB_Destroy(&fib);
+
+ // ----- Validate
+ assertTrue(hashCodeTableLength == 1, "Wrong hash table length, expected %u got %zu", 1, hashCodeTableLength);
+ assertTrue(nexthopCount == 1, "Wrong hash table length, expected %u got %zu", 1, nexthopCount);
+}
+
+LONGBOW_TEST_CASE(Global, metisFib_Remove_ExistsNotLast)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+ MetisFIB *fib = metisFIB_Create(logger);
+ metisLogger_Release(&logger);
+
+ CCNxName *ccnxNameToAdd = ccnxName_CreateFromCString("lci:/foo/bar");
+ CCNxName *ccnxNameToRemove = ccnxName_CreateFromCString("lci:/foo/bar");
+ MetisTlvName *tlvNameToCheck = metisTlvName_CreateFromCCNxName(ccnxNameToAdd);
+ unsigned interfaceIndex_1 = 11;
+ unsigned interfaceIndex_2 = 22;
+ CPIAddress *nexthop = NULL;
+ struct timeval *lifetime = NULL;
+ unsigned cost = 12;
+
+ // ----- Add two next hops
+ CPIRouteEntry *routeAdd1 = cpiRouteEntry_Create(ccnxName_Copy(ccnxNameToAdd), interfaceIndex_1, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, lifetime, cost);
+ metisFIB_AddOrUpdate(fib, routeAdd1, "random");
+
+ CPIRouteEntry *routeAdd2 = cpiRouteEntry_Create(ccnxNameToAdd, interfaceIndex_2, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, lifetime, cost);
+ metisFIB_AddOrUpdate(fib, routeAdd2, "random");
+
+ // ----- Remove
+ CPIRouteEntry *routeRemove = cpiRouteEntry_Create(ccnxNameToRemove, interfaceIndex_1, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, lifetime, cost);
+ metisFIB_Remove(fib, routeRemove);
+
+ // ----- Measure
+ size_t hashCodeTableLength = parcHashCodeTable_Length(fib->tableByName);
+ MetisFibEntry *fibEntry = parcHashCodeTable_Get(fib->tableByName, tlvNameToCheck);
+ size_t nexthopCount = metisFibEntry_NexthopCount(fibEntry);
+
+ // ----- Cleanup
+ cpiRouteEntry_Destroy(&routeAdd1);
+ cpiRouteEntry_Destroy(&routeAdd2);
+ cpiRouteEntry_Destroy(&routeRemove);
+ metisTlvName_Release(&tlvNameToCheck);
+ metisFIB_Destroy(&fib);
+
+ // ----- Validate
+ assertTrue(hashCodeTableLength == 1, "Wrong hash table length, expected %u got %zu", 1, hashCodeTableLength);
+ assertTrue(nexthopCount == 1, "Wrong hash table length, expected %u got %zu", 1, nexthopCount);
+}
+
+/**
+ * Remove the last nexthop for a route. should remove the route
+ */
+LONGBOW_TEST_CASE(Global, metisFib_Remove_ExistsIsLast)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+ MetisFIB *fib = metisFIB_Create(logger);
+ metisLogger_Release(&logger);
+
+ CCNxName *ccnxNameToAdd = ccnxName_CreateFromCString("lci:/foo/bar");
+ CCNxName *ccnxNameToRemove = ccnxName_CreateFromCString("lci:/foo/bar");
+ MetisTlvName *tlvNameToCheck = metisTlvName_CreateFromCCNxName(ccnxNameToAdd);
+ unsigned interfaceIndex_1 = 22;
+ CPIAddress *nexthop = NULL;
+ struct timeval *lifetime = NULL;
+ unsigned cost = 12;
+
+ // ----- Add
+ CPIRouteEntry *routeAdd = cpiRouteEntry_Create(ccnxNameToAdd, interfaceIndex_1, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, lifetime, cost);
+ metisFIB_AddOrUpdate(fib, routeAdd, "random");
+
+ // ----- Remove
+ CPIRouteEntry *routeRemove = cpiRouteEntry_Create(ccnxNameToRemove, interfaceIndex_1, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, lifetime, cost);
+ metisFIB_Remove(fib, routeRemove);
+
+ // ----- Measure
+ size_t hashCodeTableLength = parcHashCodeTable_Length(fib->tableByName);
+
+ // ----- Cleanup
+ cpiRouteEntry_Destroy(&routeAdd);
+ cpiRouteEntry_Destroy(&routeRemove);
+ metisTlvName_Release(&tlvNameToCheck);
+ metisFIB_Destroy(&fib);
+
+ // ----- Validate
+ assertTrue(hashCodeTableLength == 0, "Wrong hash table length, expected %u got %zu", 0, hashCodeTableLength);
+}
+
+LONGBOW_TEST_CASE(Global, metisFIB_Length)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+ MetisFIB *fib = metisFIB_Create(logger);
+
+ // CCNxName *ccnxNameToAdd = ccnxName_CreateFromCString("lci:/%02=hello/%F0%00=ouch");
+ CCNxName *ccnxNameToAdd = ccnxName_CreateFromCString("lci:/2=hello/0xF000=ouch");
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 2, logger);
+ metisLogger_Release(&logger);
+
+ unsigned interfaceIndex_1 = 22;
+ CPIAddress *nexthop = NULL;
+ struct timeval *lifetime = NULL;
+ unsigned cost = 12;
+
+ // ----- Add
+ CPIRouteEntry *routeAdd = cpiRouteEntry_Create(ccnxNameToAdd, interfaceIndex_1, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, lifetime, cost);
+ metisFIB_AddOrUpdate(fib, routeAdd, "random");
+
+ // ----- Measure
+ size_t tableLength = metisFIB_Length(fib);
+
+ // ----- Cleanup
+ cpiRouteEntry_Destroy(&routeAdd);
+ metisMessage_Release(&interest);
+ metisFIB_Destroy(&fib);
+
+ // ----- Validate
+ assertTrue(tableLength == 1, "Wrong table length, expected %u got %zu", 1, tableLength);
+}
+
+// ====================================================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, _hashTableFunction_FibEntryDestroyer);
+ LONGBOW_RUN_TEST_CASE(Local, _hashTableFunction_TlvNameDestroyer);
+ LONGBOW_RUN_TEST_CASE(Local, _metisFIB_CreateFibEntry);
+}
+
+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, _hashTableFunction_FibEntryDestroyer)
+{
+ CCNxName *ccnxName = ccnxName_CreateFromCString("lci:/foo/bar");
+ MetisTlvName *tlvName = metisTlvName_CreateFromCCNxName(ccnxName);
+ MetisFibEntry *fibEntry = metisFibEntry_Create(tlvName, "random");
+
+ _hashTableFunction_FibEntryDestroyer((void **) &fibEntry);
+
+ metisTlvName_Release(&tlvName);
+ ccnxName_Release(&ccnxName);
+ assertTrue(parcMemory_Outstanding() == 0, "Memory imbalance after hashTableFunction_TlvNameDestroyer: %u", parcMemory_Outstanding());
+}
+
+LONGBOW_TEST_CASE(Local, _hashTableFunction_TlvNameDestroyer)
+{
+ CCNxName *ccnxName = ccnxName_CreateFromCString("lci:/foo/bar");
+ MetisTlvName *tlvName = metisTlvName_CreateFromCCNxName(ccnxName);
+
+ _hashTableFunction_TlvNameDestroyer((void **) &tlvName);
+ ccnxName_Release(&ccnxName);
+
+ assertTrue(parcMemory_Outstanding() == 0, "Memory imbalance after hashTableFunction_TlvNameDestroyer: %u", parcMemory_Outstanding());
+}
+
+LONGBOW_TEST_CASE(Local, _metisFIB_CreateFibEntry)
+{
+ CCNxName *ccnxName = ccnxName_CreateFromCString("lci:/foo/bar");
+ MetisTlvName *tlvName = metisTlvName_CreateFromCCNxName(ccnxName);
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+ MetisFIB *fib = metisFIB_Create(logger);
+ metisLogger_Release(&logger);
+
+ _metisFIB_CreateFibEntry(fib, tlvName, "random");
+ size_t hashCodeTableLength = parcHashCodeTable_Length(fib->tableByName);
+
+ metisFIB_Destroy(&fib);
+ metisTlvName_Release(&tlvName);
+ ccnxName_Release(&ccnxName);
+
+ assertTrue(hashCodeTableLength == 1, "Wrong hash table size, expected %u got %zu", 1, hashCodeTableLength);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metis_FIB);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/metis/ccnx/forwarder/metis/processor/test/test_metis_FibEntry.c b/metis/ccnx/forwarder/metis/processor/test/test_metis_FibEntry.c
new file mode 100644
index 00000000..19b46d47
--- /dev/null
+++ b/metis/ccnx/forwarder/metis/processor/test/test_metis_FibEntry.c
@@ -0,0 +1,136 @@
+/*
+ * 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_FibEntry.c"
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+LONGBOW_TEST_RUNNER(metis_FibEntry)
+{
+ // 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_FibEntry)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(metis_FibEntry)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, metisFibEntry_AddNexthop);
+ LONGBOW_RUN_TEST_CASE(Global, metisFibEntry_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, metisFibEntry_SetStrategy);
+}
+
+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, metisFibEntry_AddNexthop)
+{
+ CCNxName *ccnxName = ccnxName_CreateFromCString("lci:/foo/bar");
+ MetisTlvName *tlvName = metisTlvName_CreateFromCCNxName(ccnxName);
+ MetisFibEntry *fibEntry = metisFibEntry_Create(tlvName,"random");
+
+ CCNxName *ccnxName1 = ccnxName_CreateFromCString("lci:/foo/bar");
+ CPIRouteEntry *cpiRouteEntry1 = cpiRouteEntry_Create(ccnxName1, 1, NULL, 0, 0, NULL, 1);
+ CCNxName *ccnxName2 = ccnxName_CreateFromCString("lci:/foo/bar");
+ CPIRouteEntry *cpiRouteEntry2 = cpiRouteEntry_Create(ccnxName2, 2, NULL, 0, 0, NULL, 1);
+ metisFibEntry_AddNexthop(fibEntry, cpiRouteEntry1);
+ metisFibEntry_AddNexthop(fibEntry, cpiRouteEntry2);
+
+ assertTrue(metisFibEntry_NexthopCount(fibEntry) == 2, "wrong nexthop length, expected %u got %zu", 2, metisFibEntry_NexthopCount(fibEntry));
+
+ cpiRouteEntry_Destroy(&cpiRouteEntry1);
+ cpiRouteEntry_Destroy(&cpiRouteEntry2);
+ metisFibEntry_Release(&fibEntry);
+ metisTlvName_Release(&tlvName);
+ ccnxName_Release(&ccnxName);
+}
+
+LONGBOW_TEST_CASE(Global, metisFibEntry_Create_Destroy)
+{
+ CCNxName *ccnxName = ccnxName_CreateFromCString("lci:/foo/bar");
+ MetisTlvName *tlvName = metisTlvName_CreateFromCCNxName(ccnxName);
+
+ size_t beforeMemory = parcMemory_Outstanding();
+ MetisFibEntry *fibEntry = metisFibEntry_Create(tlvName, "random");
+ metisFibEntry_Release(&fibEntry);
+ size_t afterMemory = parcMemory_Outstanding();
+
+ metisTlvName_Release(&tlvName);
+ ccnxName_Release(&ccnxName);
+
+ assertTrue(beforeMemory == afterMemory, "Memory imbalance on create/destroy: expected %zu got %zu", beforeMemory, afterMemory);
+}
+
+
+LONGBOW_TEST_CASE(Global, metisFibEntry_SetStrategy)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+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_FibEntry);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/metis/ccnx/forwarder/metis/processor/test/test_metis_FibEntryList.c b/metis/ccnx/forwarder/metis/processor/test/test_metis_FibEntryList.c
new file mode 100644
index 00000000..25de216b
--- /dev/null
+++ b/metis/ccnx/forwarder/metis/processor/test/test_metis_FibEntryList.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../metis_FibEntryList.c"
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(metis_FibEntryList)
+{
+ // 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_FibEntryList)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(metis_FibEntryList)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, metisFibEntryList_Append);
+ LONGBOW_RUN_TEST_CASE(Global, metisFibEntryList_Create);
+ LONGBOW_RUN_TEST_CASE(Global, metisFibEntryList_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, metisFibEntryList_Get);
+ LONGBOW_RUN_TEST_CASE(Global, metisFibEntryList_Length);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, metisFibEntryList_Append)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, metisFibEntryList_Create)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, metisFibEntryList_Destroy)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, metisFibEntryList_Get)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, metisFibEntryList_Length)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, metisFibEntryList_ListDestroyer);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Local, metisFibEntryList_ListDestroyer)
+{
+ testUnimplemented("");
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metis_FibEntryList);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/metis/ccnx/forwarder/metis/processor/test/test_metis_HashTableFunction.c b/metis/ccnx/forwarder/metis/processor/test/test_metis_HashTableFunction.c
new file mode 100644
index 00000000..8f61cfb0
--- /dev/null
+++ b/metis/ccnx/forwarder/metis/processor/test/test_metis_HashTableFunction.c
@@ -0,0 +1,133 @@
+/*
+ * 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_HashTableFunction.c"
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(metis_HashTableFunction)
+{
+ // 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_HashTableFunction)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(metis_HashTableFunction)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, metisHashTableFunction_MessageNameAndKeyIdEquals);
+ LONGBOW_RUN_TEST_CASE(Global, metisHashTableFunction_MessageNameAndKeyIdHashCode);
+ LONGBOW_RUN_TEST_CASE(Global, metisHashTableFunction_MessageNameAndObjectHashEquals);
+ LONGBOW_RUN_TEST_CASE(Global, metisHashTableFunction_MessageNameAndObjectHashHashCode);
+ LONGBOW_RUN_TEST_CASE(Global, metisHashTableFunction_MessageNameEquals);
+ LONGBOW_RUN_TEST_CASE(Global, metisHashTableFunction_MessageNameHashCode);
+ LONGBOW_RUN_TEST_CASE(Global, metisHashTableFunction_TlvNameCompare);
+ LONGBOW_RUN_TEST_CASE(Global, metisHashTableFunction_TlvNameEquals);
+ LONGBOW_RUN_TEST_CASE(Global, metisHashTableFunction_TlvNameHashCode);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, metisHashTableFunction_MessageNameAndKeyIdEquals)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, metisHashTableFunction_MessageNameAndKeyIdHashCode)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, metisHashTableFunction_MessageNameAndObjectHashEquals)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, metisHashTableFunction_MessageNameAndObjectHashHashCode)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, metisHashTableFunction_MessageNameEquals)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, metisHashTableFunction_MessageNameHashCode)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, metisHashTableFunction_TlvNameCompare)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, metisHashTableFunction_TlvNameEquals)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Global, metisHashTableFunction_TlvNameHashCode)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metis_HashTableFunction);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/metis/ccnx/forwarder/metis/processor/test/test_metis_MatchingRulesTable.c b/metis/ccnx/forwarder/metis/processor/test/test_metis_MatchingRulesTable.c
new file mode 100644
index 00000000..63e31dea
--- /dev/null
+++ b/metis/ccnx/forwarder/metis/processor/test/test_metis_MatchingRulesTable.c
@@ -0,0 +1,666 @@
+/*
+ * 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_MatchingRulesTable.c"
+#include <LongBow/unit-test.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/logging/parc_LogReporterTextStdout.h>
+
+#include <ccnx/forwarder/metis/testdata/metis_TestDataV0.h>
+
+LONGBOW_TEST_RUNNER(metis_MatchingRulesTable)
+{
+ // 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);
+ LONGBOW_RUN_TEST_FIXTURE(HashFunctions);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(metis_MatchingRulesTable)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(metis_MatchingRulesTable)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ============================================================================
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, metisMatchingRulesTable_Create_Destroy);
+
+ LONGBOW_RUN_TEST_CASE(Global, metisMatchingRulesTable_Add_ByName);
+ LONGBOW_RUN_TEST_CASE(Global, metisMatchingRulesTable_Add_ByNameAndKeyId);
+ LONGBOW_RUN_TEST_CASE(Global, metisMatchingRulesTable_Add_ByNameAndObjectHash);
+ LONGBOW_RUN_TEST_CASE(Global, metisMatchingRulesTable_AddToAllTables);
+
+ LONGBOW_RUN_TEST_CASE(Global, metisMatchingRulesTable_Get);
+ LONGBOW_RUN_TEST_CASE(Global, metisMatchingRulesTable_RemoveFromBest);
+ LONGBOW_RUN_TEST_CASE(Global, metisMatchingRulesTable_RemoveFromAll);
+
+ LONGBOW_RUN_TEST_CASE(Global, metisMatchingRulesTable_GetUnion_NoMatch);
+ LONGBOW_RUN_TEST_CASE(Global, metisMatchingRulesTable_GetUnion_1Table);
+ LONGBOW_RUN_TEST_CASE(Global, metisMatchingRulesTable_GetUnion_2Tables);
+ LONGBOW_RUN_TEST_CASE(Global, metisMatchingRulesTable_GetUnion_3Tables);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, metisMatchingRulesTable_Add_ByName)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ parcLogReporter_Release(&reporter);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 1, logger);
+ metisLogger_Release(&logger);
+
+ MetisMatchingRulesTable *rulesTable = metisMatchingRulesTable_Create(NULL);
+ void *data = (void *) 0x01;
+
+ metisMatchingRulesTable_AddToBestTable(rulesTable, interest, data);
+ size_t tableLength = parcHashCodeTable_Length(rulesTable->tableByName);
+
+ metisMatchingRulesTable_Destroy(&rulesTable);
+ metisMessage_Release(&interest);
+
+ assertTrue(tableLength == 1, "tableByName wrong length, expected %u got %zu", 1, tableLength);
+}
+
+LONGBOW_TEST_CASE(Global, metisMatchingRulesTable_Add_ByNameAndKeyId)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ parcLogReporter_Release(&reporter);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName_keyid, sizeof(metisTestDataV0_InterestWithName_keyid), 1, 1, logger);
+ metisLogger_Release(&logger);
+ MetisMatchingRulesTable *rulesTable = metisMatchingRulesTable_Create(NULL);
+ void *data = (void *) 0x01;
+
+ metisMatchingRulesTable_AddToBestTable(rulesTable, interest, data);
+ size_t tableLength = parcHashCodeTable_Length(rulesTable->tableByNameAndKeyId);
+
+ metisMatchingRulesTable_Destroy(&rulesTable);
+ metisMessage_Release(&interest);
+
+ assertTrue(tableLength == 1, "tableByNameAndKeyId wrong length, expected %u got %zu", 1, tableLength);
+}
+
+LONGBOW_TEST_CASE(Global, metisMatchingRulesTable_Add_ByNameAndObjectHash)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ parcLogReporter_Release(&reporter);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName_objecthash, sizeof(metisTestDataV0_InterestWithName_objecthash), 1, 1, logger);
+ metisLogger_Release(&logger);
+ MetisMatchingRulesTable *rulesTable = metisMatchingRulesTable_Create(NULL);
+ void *data = (void *) 0x01;
+
+ metisMatchingRulesTable_AddToBestTable(rulesTable, interest, data);
+ size_t tableLength = parcHashCodeTable_Length(rulesTable->tableByNameAndObjectHash);
+
+ metisMatchingRulesTable_Destroy(&rulesTable);
+ metisMessage_Release(&interest);
+
+ assertTrue(tableLength == 1, "tableByNameAndObjectHash wrong length, expected %u got %zu", 1, tableLength);
+}
+
+LONGBOW_TEST_CASE(Global, metisMatchingRulesTable_AddToAllTables)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ parcLogReporter_Release(&reporter);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName_objecthash, sizeof(metisTestDataV0_InterestWithName_objecthash), 1, 1, logger);
+ metisLogger_Release(&logger);
+ MetisMatchingRulesTable *rulesTable = metisMatchingRulesTable_Create(NULL);
+ void *data = (void *) 0x01;
+
+ metisMatchingRulesTable_AddToAllTables(rulesTable, interest, data);
+ size_t tableLength = parcHashCodeTable_Length(rulesTable->tableByNameAndObjectHash);
+ assertTrue(tableLength == 1, "tableToAllTables wrong length, expected %u got %zu", 1, tableLength);
+
+ metisMatchingRulesTable_Destroy(&rulesTable);
+ metisMessage_Release(&interest);
+
+}
+
+LONGBOW_TEST_CASE(Global, metisMatchingRulesTable_Create_Destroy)
+{
+ size_t baselineMemory = parcMemory_Outstanding();
+
+ MetisMatchingRulesTable *rulesTable = metisMatchingRulesTable_Create(NULL);
+ metisMatchingRulesTable_Destroy(&rulesTable);
+
+ assertTrue(parcMemory_Outstanding() == baselineMemory, "Memory imbalance on create/destroy: %u", parcMemory_Outstanding());
+}
+
+LONGBOW_TEST_CASE(Global, metisMatchingRulesTable_Get)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ parcLogReporter_Release(&reporter);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName_objecthash, sizeof(metisTestDataV0_InterestWithName_objecthash), 1, 1, logger);
+ metisLogger_Release(&logger);
+ MetisMatchingRulesTable *rulesTable = metisMatchingRulesTable_Create(NULL);
+ void *data = (void *) 0x01;
+
+ metisMatchingRulesTable_AddToBestTable(rulesTable, interest, data);
+ void *test = metisMatchingRulesTable_Get(rulesTable, interest);
+
+ metisMatchingRulesTable_Destroy(&rulesTable);
+ metisMessage_Release(&interest);
+
+ assertTrue(data == test, "metisMatchingRulesTable_Get returned wrong result, expected %p got %p", data, test);
+}
+
+LONGBOW_TEST_CASE(Global, metisMatchingRulesTable_RemoveFromAll)
+{
+ MetisMatchingRulesTable *rulesTable = metisMatchingRulesTable_Create(NULL);
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ parcLogReporter_Release(&reporter);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 1, logger);
+ metisLogger_Release(&logger);
+ void *data = (void *) 0x01;
+
+ size_t before = parcHashCodeTable_Length(rulesTable->tableByName);
+ parcHashCodeTable_Add(rulesTable->tableByName, interest, data);
+ metisMatchingRulesTable_RemoveFromAll(rulesTable, interest);
+ size_t after = parcHashCodeTable_Length(rulesTable->tableByName);
+
+ metisMessage_Release(&interest);
+ metisMatchingRulesTable_Destroy(&rulesTable);
+
+ assertTrue(after == before, "Did not remove interest in HashCodeTable: before %zu after %zu", before, after);
+}
+
+LONGBOW_TEST_CASE(Global, metisMatchingRulesTable_RemoveFromBest)
+{
+ MetisMatchingRulesTable *rulesTable = metisMatchingRulesTable_Create(NULL);
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ parcLogReporter_Release(&reporter);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 1, logger);
+ metisLogger_Release(&logger);
+ void *data = (void *) 0x01;
+
+ size_t before = parcHashCodeTable_Length(rulesTable->tableByName);
+ parcHashCodeTable_Add(rulesTable->tableByName, interest, data);
+ metisMatchingRulesTable_RemoveFromBest(rulesTable, interest);
+ size_t after = parcHashCodeTable_Length(rulesTable->tableByName);
+
+ metisMessage_Release(&interest);
+ metisMatchingRulesTable_Destroy(&rulesTable);
+
+ assertTrue(after == before, "Did not remove interest in HashCodeTable: before %zu after %zu", before, after);
+}
+
+LONGBOW_TEST_CASE(Global, metisMatchingRulesTable_GetUnion_NoMatch)
+{
+ MetisMatchingRulesTable *rulesTable = metisMatchingRulesTable_Create(NULL);
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ parcLogReporter_Release(&reporter);
+ MetisMessage *object = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 1, logger);
+ metisLogger_Release(&logger);
+
+ PARCArrayList *list = metisMatchingRulesTable_GetUnion(rulesTable, object);
+ assertTrue(parcArrayList_Size(list) == 0, "Incorrect result length, expected %u got %zu", 0, parcArrayList_Size(list));
+
+ parcArrayList_Destroy(&list);
+ metisMessage_Release(&object);
+ metisMatchingRulesTable_Destroy(&rulesTable);
+}
+
+LONGBOW_TEST_CASE(Global, metisMatchingRulesTable_GetUnion_1Table)
+{
+ MetisMatchingRulesTable *rulesTable = metisMatchingRulesTable_Create(NULL);
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ parcLogReporter_Release(&reporter);
+ MetisMessage *interestByName = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 2, logger);
+ void *data = (void *) 0x01;
+
+ // add the interest to the table
+ metisMatchingRulesTable_AddToBestTable(rulesTable, interestByName, data);
+
+ // now retrieve it with a matching content object
+ MetisMessage *object = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 4, logger);
+
+ PARCArrayList *list = metisMatchingRulesTable_GetUnion(rulesTable, object);
+ assertTrue(parcArrayList_Size(list) == 1, "Incorrect result length, expected %u got %zu", 1, parcArrayList_Size(list));
+
+ metisLogger_Release(&logger);
+ parcArrayList_Destroy(&list);
+ metisMessage_Release(&object);
+ metisMessage_Release(&interestByName);
+ metisMatchingRulesTable_Destroy(&rulesTable);
+}
+
+LONGBOW_TEST_CASE(Global, metisMatchingRulesTable_GetUnion_2Tables)
+{
+ MetisMatchingRulesTable *rulesTable = metisMatchingRulesTable_Create(NULL);
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ parcLogReporter_Release(&reporter);
+ MetisMessage *interestByName = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 2, logger);
+ MetisMessage *interestByNameAndKeyId = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName_keyid, sizeof(metisTestDataV0_InterestWithName_keyid), 1, 2, logger);
+ void *data = (void *) 0x01;
+
+ // add the interest to the tables
+ metisMatchingRulesTable_AddToBestTable(rulesTable, interestByName, data);
+ metisMatchingRulesTable_AddToBestTable(rulesTable, interestByNameAndKeyId, data);
+
+ // now retrieve it with a matching content object
+ MetisMessage *object = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 4, logger);
+
+ PARCArrayList *list = metisMatchingRulesTable_GetUnion(rulesTable, object);
+ assertTrue(parcArrayList_Size(list) == 2, "Incorrect result length, expected %u got %zu", 2, parcArrayList_Size(list));
+
+ metisLogger_Release(&logger);
+ parcArrayList_Destroy(&list);
+ metisMessage_Release(&object);
+ metisMessage_Release(&interestByName);
+ metisMessage_Release(&interestByNameAndKeyId);
+ metisMatchingRulesTable_Destroy(&rulesTable);
+}
+
+LONGBOW_TEST_CASE(Global, metisMatchingRulesTable_GetUnion_3Tables)
+{
+ MetisMatchingRulesTable *rulesTable = metisMatchingRulesTable_Create(NULL);
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ parcLogReporter_Release(&reporter);
+ MetisMessage *interestByName = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 2, logger);
+ MetisMessage *interestByNameAndKeyId = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName_keyid, sizeof(metisTestDataV0_InterestWithName_keyid), 1, 2, logger);
+ MetisMessage *interestByNameAndObjectHash = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName_objecthash, sizeof(metisTestDataV0_InterestWithName_objecthash), 1, 2, logger);
+ void *data = (void *) 0x01;
+
+ // add the interest to the tables
+ assertTrue(metisMatchingRulesTable_AddToBestTable(rulesTable, interestByName, data), "Cannot add interestByName");
+ assertTrue(metisMatchingRulesTable_AddToBestTable(rulesTable, interestByNameAndKeyId, data), "Cannot add interestByNameAndKeyId");
+ assertTrue(metisMatchingRulesTable_AddToBestTable(rulesTable, interestByNameAndObjectHash, data), "Cannot add interestByNameAndObjectHash");
+
+ // now retrieve it with a matching content object
+ MetisMessage *object = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 4, logger);
+
+ PARCArrayList *list = metisMatchingRulesTable_GetUnion(rulesTable, object);
+ assertTrue(parcArrayList_Size(list) == 3, "Incorrect result length, expected %u got %zu", 3, parcArrayList_Size(list));
+
+ metisLogger_Release(&logger);
+ parcArrayList_Destroy(&list);
+ metisMessage_Release(&object);
+ metisMessage_Release(&interestByName);
+ metisMessage_Release(&interestByNameAndKeyId);
+ metisMessage_Release(&interestByNameAndObjectHash);
+ metisMatchingRulesTable_Destroy(&rulesTable);
+}
+
+// ============================================================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, metisMatchingRulesTable_GetTableForMessage_TableByNameAndObjectHash);
+ LONGBOW_RUN_TEST_CASE(Local, metisMatchingRulesTable_GetTableForMessage_TableByNameAndKeyId);
+ LONGBOW_RUN_TEST_CASE(Local, metisMatchingRulesTable_GetTableForMessage_TableByName);
+}
+
+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;
+}
+
+/**
+ * Use an interest with only a name, should select tableByName
+ */
+LONGBOW_TEST_CASE(Local, metisMatchingRulesTable_GetTableForMessage_TableByName)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ parcLogReporter_Release(&reporter);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 1, logger);
+ metisLogger_Release(&logger);
+
+ MetisMatchingRulesTable *rulesTable = metisMatchingRulesTable_Create(NULL);
+ PARCHashCodeTable *table = metisMatchingRulesTable_GetTableForMessage(rulesTable, interest);
+
+ assertTrue(table == rulesTable->tableByName,
+ "Chose wrong table, expected TableByName, got %s",
+ (table == rulesTable->tableByNameAndKeyId) ? "tableByNameAndKeyId" :
+ (table == rulesTable->tableByNameAndObjectHash) ? "tableByNameAndObjectHash" : "unknown");
+
+ metisMatchingRulesTable_Destroy(&rulesTable);
+ metisMessage_Release(&interest);
+}
+
+/**
+ * Use an interest with a name and keyid, should select tableByNameAndKeyId
+ */
+LONGBOW_TEST_CASE(Local, metisMatchingRulesTable_GetTableForMessage_TableByNameAndKeyId)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ parcLogReporter_Release(&reporter);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName_keyid, sizeof(metisTestDataV0_InterestWithName_keyid), 1, 1, logger);
+ metisLogger_Release(&logger);
+
+ MetisMatchingRulesTable *rulesTable = metisMatchingRulesTable_Create(NULL);
+ PARCHashCodeTable *table = metisMatchingRulesTable_GetTableForMessage(rulesTable, interest);
+
+ assertTrue(table == rulesTable->tableByNameAndKeyId,
+ "Chose wrong table, expected TableByNameAndKeyId, got %s",
+ (table == rulesTable->tableByName) ? "tableByName" :
+ (table == rulesTable->tableByNameAndObjectHash) ? "tableByNameAndObjectHash" : "unknown");
+
+ metisMatchingRulesTable_Destroy(&rulesTable);
+ metisMessage_Release(&interest);
+}
+
+/**
+ * Use an interest with a name and objecthash, should select tableByNameAndObjectHash
+ */
+LONGBOW_TEST_CASE(Local, metisMatchingRulesTable_GetTableForMessage_TableByNameAndObjectHash)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ parcLogReporter_Release(&reporter);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName_objecthash, sizeof(metisTestDataV0_InterestWithName_objecthash), 1, 1, logger);
+ metisLogger_Release(&logger);
+
+ MetisMatchingRulesTable *rulesTable = metisMatchingRulesTable_Create(NULL);
+ PARCHashCodeTable *table = metisMatchingRulesTable_GetTableForMessage(rulesTable, interest);
+
+ assertTrue(table == rulesTable->tableByNameAndObjectHash,
+ "Chose wrong table, expected TableByName, got %s",
+ (table == rulesTable->tableByNameAndKeyId) ? "tableByNameAndKeyId" :
+ (table == rulesTable->tableByName) ? "tableByName" : "unknown");
+
+ metisMatchingRulesTable_Destroy(&rulesTable);
+ metisMessage_Release(&interest);
+}
+
+// ============================================================================
+
+LONGBOW_TEST_FIXTURE(HashFunctions)
+{
+ LONGBOW_RUN_TEST_CASE(HashFunctions, hashTableFunction_NameAndKeyIdEquals_IsEqual);
+ LONGBOW_RUN_TEST_CASE(HashFunctions, hashTableFunction_NameAndKeyIdEquals_IsNotEqual);
+ LONGBOW_RUN_TEST_CASE(HashFunctions, hashTableFunction_NameAndKeyIdHashCode);
+
+ LONGBOW_RUN_TEST_CASE(HashFunctions, hashTableFunction_NameAndObjectHashEquals_IsEqual);
+ LONGBOW_RUN_TEST_CASE(HashFunctions, hashTableFunction_NameAndObjectHashEquals_IsNotEqual);
+ LONGBOW_RUN_TEST_CASE(HashFunctions, hashTableFunction_NameAndObjectHashHashCode);
+
+ LONGBOW_RUN_TEST_CASE(HashFunctions, hashTableFunction_NameEquals_IsEqual);
+ LONGBOW_RUN_TEST_CASE(HashFunctions, hashTableFunction_NameEquals_IsNotEqual);
+ LONGBOW_RUN_TEST_CASE(HashFunctions, hashTableFunction_NameHashCode);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(HashFunctions)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(HashFunctions)
+{
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+/**
+ * Test an interest and content object that match on (Name, KeyId)
+ */
+LONGBOW_TEST_CASE(HashFunctions, hashTableFunction_NameAndKeyIdEquals_IsEqual)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ parcLogReporter_Release(&reporter);
+ MetisMessage *a = metisMessage_CreateFromArray(metisTestDataV0_EncodedInterest, sizeof(metisTestDataV0_EncodedInterest), 1, 1, logger);
+ MetisMessage *b = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 1, logger);
+ metisLogger_Release(&logger);
+
+ bool success = metisHashTableFunction_MessageNameAndKeyIdEquals(a, b);
+
+ metisMessage_Release(&a);
+ metisMessage_Release(&b);
+
+ assertTrue(success, "Two equal names and keyids did not compare equal");
+}
+
+/**
+ * Test two interests that do not match on (Name, KeyId)
+ */
+LONGBOW_TEST_CASE(HashFunctions, hashTableFunction_NameAndKeyIdEquals_IsNotEqual)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ parcLogReporter_Release(&reporter);
+ MetisMessage *a = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName_keyid, sizeof(metisTestDataV0_InterestWithName_keyid), 1, 1, logger);
+ MetisMessage *b = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName_keyid2, sizeof(metisTestDataV0_InterestWithName_keyid2), 1, 1, logger);
+ metisLogger_Release(&logger);
+
+ bool success = metisHashTableFunction_MessageNameAndKeyIdEquals(a, b);
+
+ metisMessage_Release(&a);
+ metisMessage_Release(&b);
+
+ assertFalse(success, "Two unequal names compared equal");
+}
+
+LONGBOW_TEST_CASE(HashFunctions, hashTableFunction_NameAndKeyIdHashCode)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ parcLogReporter_Release(&reporter);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName_keyid, sizeof(metisTestDataV0_InterestWithName_keyid), 1, 1, logger);
+ metisLogger_Release(&logger);
+
+ MetisTlvName *name = metisMessage_GetName(interest);
+ uint32_t name_hash = metisTlvName_HashCode(name);
+ uint32_t keyid_hash;
+ metisMessage_GetKeyIdHash(interest, &keyid_hash);
+
+ HashCodeType truth_hash = parcHash32_Data_Cumulative(&keyid_hash, sizeof(keyid_hash), name_hash);
+
+ // the function to test
+ HashCodeType test_hash = metisHashTableFunction_MessageNameAndKeyIdHashCode(interest);
+
+ metisMessage_Release(&interest);
+
+ assertTrue(test_hash == truth_hash, "Got wrong hash, expected %08"PRIX64 " got %08"PRIX64, truth_hash, test_hash);
+}
+
+LONGBOW_TEST_CASE(HashFunctions, hashTableFunction_NameAndObjectHashEquals_IsEqual)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ parcLogReporter_Release(&reporter);
+ MetisMessage *a = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName_objecthash, sizeof(metisTestDataV0_InterestWithName_objecthash), 1, 1, logger);
+ MetisMessage *b = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 1, logger);
+ metisLogger_Release(&logger);
+
+ bool success = metisHashTableFunction_MessageNameAndObjectHashEquals(a, b);
+
+ metisMessage_Release(&a);
+ metisMessage_Release(&b);
+
+ assertTrue(success, "Two equal names and hashes did not compare equal");
+}
+
+LONGBOW_TEST_CASE(HashFunctions, hashTableFunction_NameAndObjectHashEquals_IsNotEqual)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ parcLogReporter_Release(&reporter);
+ MetisMessage *a = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName_objecthash, sizeof(metisTestDataV0_InterestWithName_objecthash), 1, 1, logger);
+ MetisMessage *b = metisMessage_CreateFromArray(metisTestDataV0_SecondObject, sizeof(metisTestDataV0_SecondObject), 1, 1, logger);
+ metisLogger_Release(&logger);
+
+ bool success = metisHashTableFunction_MessageNameAndObjectHashEquals(a, b);
+
+ metisMessage_Release(&a);
+ metisMessage_Release(&b);
+
+ assertFalse(success, "Two unequal names and hashes compared equal");
+}
+
+LONGBOW_TEST_CASE(HashFunctions, hashTableFunction_NameAndObjectHashHashCode)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ parcLogReporter_Release(&reporter);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName_objecthash, sizeof(metisTestDataV0_InterestWithName_objecthash), 1, 1, logger);
+ metisLogger_Release(&logger);
+
+ MetisTlvName *name = metisMessage_GetName(interest);
+ uint32_t name_hash = metisTlvName_HashCode(name);
+ uint32_t object_hash;
+ metisMessage_GetContentObjectHashHash(interest, &object_hash);
+
+ HashCodeType truth_hash = parcHash32_Data_Cumulative(&object_hash, sizeof(object_hash), name_hash);
+
+ // the function we actually want to test
+ HashCodeType test_hash = (HashCodeType)metisHashTableFunction_MessageNameAndObjectHashHashCode(interest);
+
+ metisMessage_Release(&interest);
+
+ assertTrue(test_hash == truth_hash, "Got wrong hash, expected %08"PRIX64 " got %08"PRIX64 , truth_hash, test_hash);
+}
+
+/**
+ * Takes two MetisMessage and compares their names for equality
+ */
+LONGBOW_TEST_CASE(HashFunctions, hashTableFunction_NameEquals_IsEqual)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ parcLogReporter_Release(&reporter);
+ MetisMessage *a = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 1, logger);
+ MetisMessage *b = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName_keyid, sizeof(metisTestDataV0_InterestWithName_keyid), 1, 1, logger);
+ metisLogger_Release(&logger);
+
+ bool success = metisHashTableFunction_MessageNameEquals(a, b);
+
+ metisMessage_Release(&a);
+ metisMessage_Release(&b);
+
+ assertTrue(success, "Two equal names did not compare equal");
+}
+
+/**
+ * test two interests with different names
+ */
+LONGBOW_TEST_CASE(HashFunctions, hashTableFunction_NameEquals_IsNotEqual)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ parcLogReporter_Release(&reporter);
+ MetisMessage *a = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 1, logger);
+ MetisMessage *b = metisMessage_CreateFromArray(metisTestDataV0_InterestWithOtherName, sizeof(metisTestDataV0_InterestWithOtherName), 1, 1, logger);
+ metisLogger_Release(&logger);
+
+ bool success = metisHashTableFunction_MessageNameEquals(a, b);
+
+ metisMessage_Release(&a);
+ metisMessage_Release(&b);
+
+ assertFalse(success, "Two unequal names compared equal");
+}
+
+/**
+ * Used on a MetisMessage key type, should return the HashCode
+ * of the message's name
+ */
+LONGBOW_TEST_CASE(HashFunctions, hashTableFunction_NameHashCode)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ parcLogReporter_Release(&reporter);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 1, logger);
+ metisLogger_Release(&logger);
+
+ MetisTlvName *name = metisMessage_GetName(interest);
+ HashCodeType truth_hash = (HashCodeType)metisTlvName_HashCode(name);
+ HashCodeType test_hash = metisHashTableFunction_MessageNameHashCode(interest);
+
+ metisMessage_Release(&interest);
+
+ assertTrue(test_hash == truth_hash, "Got wrong hash, expected %08"PRIX64 " got %08"PRIX64, truth_hash, test_hash);
+}
+
+// ============================================================================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metis_MatchingRulesTable);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/metis/ccnx/forwarder/metis/processor/test/test_metis_MessageProcessor.c b/metis/ccnx/forwarder/metis/processor/test/test_metis_MessageProcessor.c
new file mode 100644
index 00000000..1da3ca94
--- /dev/null
+++ b/metis/ccnx/forwarder/metis/processor/test/test_metis_MessageProcessor.c
@@ -0,0 +1,1533 @@
+/*
+ * 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_MessageProcessor.c"
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <ccnx/forwarder/metis/testdata/metis_TestDataV0.h>
+#include <ccnx/forwarder/metis/testdata/metis_TestDataV1.h>
+#include "../../core/test/testrig_MetisIoOperations.h"
+
+// Include this so we can step the clock forward without waiting real time
+#include "../../core/metis_Forwarder.c"
+
+#include "testrig_MockTap.h"
+
+// =========================================================================
+
+LONGBOW_TEST_RUNNER(metis_MessageProcessor)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+
+ 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_MessageProcessor)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(metis_MessageProcessor)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, metisMessageProcessor_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, metisMessageProcessor_AddTap);
+
+ LONGBOW_RUN_TEST_CASE(Global, metisMessageProcessor_Receive_WithTap);
+ LONGBOW_RUN_TEST_CASE(Global, metisMessageProcessor_Receive_Interest_WithoutTap);
+ LONGBOW_RUN_TEST_CASE(Global, metisMessageProcessor_Receive_Object_WithoutTap);
+
+ LONGBOW_RUN_TEST_CASE(Global, metisMessageProcessor_RemoveTap_RemoveCurrentTap);
+ LONGBOW_RUN_TEST_CASE(Global, metisMessageProcessor_RemoveTap_RemoveOtherTap);
+
+ LONGBOW_RUN_TEST_CASE(Global, metisMessageProcessor_AddOrUpdateRoute);
+ LONGBOW_RUN_TEST_CASE(Global, metisMessageProcessor_RemoveRoute);
+
+ LONGBOW_RUN_TEST_CASE(Global, metisMessageProcessor_SetContentStoreSize);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ memset(&testTap, 0, sizeof(testTap));
+ 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, metisMessageProcessor_Create_Destroy)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+
+ uint32_t beforeBalance = parcMemory_Outstanding();
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+ metisMessageProcessor_Destroy(&processor);
+ uint32_t afterBalance = parcMemory_Outstanding();
+
+ metisForwarder_Destroy(&metis);
+ assertTrue(beforeBalance == afterBalance, "Memory imbalance on create/destroy: before %u after %u", beforeBalance, afterBalance);
+}
+
+LONGBOW_TEST_CASE(Global, metisMessageProcessor_AddTap)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+
+ metisMessageProcessor_AddTap(processor, &testTapTemplate);
+ void *currentTap = processor->tap;
+
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+
+ assertTrue(currentTap == &testTapTemplate, "tap did not get set correctly, expected %p got %p", (void *) &testTapTemplate, currentTap);
+}
+
+LONGBOW_TEST_CASE(Global, metisMessageProcessor_Receive_WithTap)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+
+ testTap.callOnReceive = true;
+ metisMessageProcessor_AddTap(processor, &testTapTemplate);
+
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 4, 5, logger);
+
+ // now test the function and measure results
+ metisMessageProcessor_Receive(processor, interest);
+
+ // cleanup
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+
+ // validate
+ assertTrue(testTap.onReceiveCount == 1, "Incorrect testTap.onReceiveCount, expected %u got %u", 1, testTap.onReceiveCount);
+}
+
+LONGBOW_TEST_CASE(Global, metisMessageProcessor_Receive_Interest_WithoutTap)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 4, 5, logger);
+
+ // now test the function and measure results
+ uint32_t beforeCountReceived = processor->stats.countReceived;
+ uint32_t beforeCountInterestsReceived = processor->stats.countInterestsReceived;
+ metisMessageProcessor_Receive(processor, interest);
+ uint32_t afterCountInterestsReceived = processor->stats.countInterestsReceived;
+ uint32_t afterCountReceived = processor->stats.countReceived;
+
+ // cleanup
+ // do not cleanup interest, metisMessageProcessor_Receive() takes ownership
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+
+ // validate
+ assertTrue(afterCountReceived == beforeCountReceived + 1,
+ "Incorrect afterCountReceived, expected %u got %u",
+ beforeCountReceived + 1,
+ afterCountReceived);
+
+ assertTrue(afterCountInterestsReceived == beforeCountInterestsReceived + 1,
+ "Incorrect afterCountInterestsReceived, expected %u got %u",
+ beforeCountInterestsReceived + 1,
+ afterCountInterestsReceived);
+}
+
+LONGBOW_TEST_CASE(Global, metisMessageProcessor_Receive_Object_WithoutTap)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ MetisMessage *object = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 4, 5, logger);
+
+
+ // now test the function and measure results
+ uint32_t beforeCountReceived = processor->stats.countReceived;
+ uint32_t beforeCountObjectsReceived = processor->stats.countObjectsReceived;
+ metisMessageProcessor_Receive(processor, object);
+ uint32_t afterCountObjectsReceived = processor->stats.countObjectsReceived;
+ uint32_t afterCountReceived = processor->stats.countReceived;
+
+ // cleanup
+ // do not cleanup object, metisMessageProcessor_Receive() takes ownership
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+
+ // validate
+ assertTrue(afterCountReceived == beforeCountReceived + 1,
+ "Incorrect afterCountReceived, expected %u got %u",
+ beforeCountReceived + 1,
+ afterCountReceived);
+
+ assertTrue(afterCountObjectsReceived == beforeCountObjectsReceived + 1,
+ "Incorrect afterCountInterestsReceived, expected %u got %u",
+ afterCountObjectsReceived,
+ beforeCountObjectsReceived + 1);
+}
+
+LONGBOW_TEST_CASE(Global, metisMessageProcessor_RemoveTap_RemoveCurrentTap)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+
+ metisMessageProcessor_AddTap(processor, &testTapTemplate);
+ metisMessageProcessor_RemoveTap(processor, &testTapTemplate);
+ void *currentTap = processor->tap;
+
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+
+ assertTrue(currentTap == NULL, "tap did not get removed correctly, expected %p got %p", NULL, currentTap);
+}
+
+/**
+ * If we remove a tap that is not currently set, should have no effect.
+ */
+LONGBOW_TEST_CASE(Global, metisMessageProcessor_RemoveTap_RemoveOtherTap)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+
+ MetisTap otherTap;
+
+ metisMessageProcessor_AddTap(processor, &testTapTemplate);
+ metisMessageProcessor_RemoveTap(processor, &otherTap);
+ void *currentTap = processor->tap;
+
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+
+ assertTrue(currentTap == &testTapTemplate, "tap incorrectly removed, expected %p got %p", (void *) &testTapTemplate, currentTap);
+}
+
+LONGBOW_TEST_CASE(Global, metisMessageProcessor_AddOrUpdateRoute)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+
+ CCNxName *ccnxName = ccnxName_CreateFromCString("lci:/foo/bar");
+ MetisTlvName *tlvName = metisTlvName_CreateFromCCNxName(ccnxName);
+ unsigned interfaceIndex = 22;
+ CPIAddress *nexthop = NULL;
+ struct timeval *lifetime = NULL;
+ unsigned cost = 12;
+
+ CPIRouteEntry *route = cpiRouteEntry_Create(ccnxName, interfaceIndex, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, lifetime, cost);
+
+ metisMessageProcessor_AddOrUpdateRoute(processor, route);
+
+ size_t hashCodeTableLength = metisFIB_Length(processor->fib);
+
+ cpiRouteEntry_Destroy(&route);
+ metisTlvName_Release(&tlvName);
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+
+ assertTrue(hashCodeTableLength == 1, "Wrong hash table length, expected %u got %zu", 1, hashCodeTableLength);
+}
+
+LONGBOW_TEST_CASE(Global, metisMessageProcessor_RemoveRoute)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+
+ CCNxName *ccnxName = ccnxName_CreateFromCString("lci:/foo/bar");
+ MetisTlvName *tlvName = metisTlvName_CreateFromCCNxName(ccnxName);
+ unsigned interfaceIndex = 22;
+ CPIAddress *nexthop = NULL;
+ struct timeval *lifetime = NULL;
+ unsigned cost = 12;
+
+ CPIRouteEntry *route = cpiRouteEntry_Create(ccnxName, interfaceIndex, nexthop, cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, lifetime, cost);
+
+ metisMessageProcessor_AddOrUpdateRoute(processor, route);
+ metisMessageProcessor_RemoveRoute(processor, route);
+
+ size_t hashCodeTableLength = metisFIB_Length(processor->fib);
+
+ cpiRouteEntry_Destroy(&route);
+ metisTlvName_Release(&tlvName);
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+
+ assertTrue(hashCodeTableLength == 0, "Wrong hash table length, expected %u got %zu", 0, hashCodeTableLength);
+}
+
+LONGBOW_TEST_CASE(Global, metisMessageProcessor_SetContentStoreSize)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+
+ size_t newCapacity = 1234;
+ metisForwarder_SetContentObjectStoreSize(metis, newCapacity);
+
+ MetisContentStoreInterface *storeImpl = metisMessageProcessor_GetContentObjectStore(metis->processor);
+
+ size_t testCapacity = metisContentStoreInterface_GetObjectCapacity(storeImpl);
+ assertTrue(testCapacity == newCapacity, "Expected the new store capacity");
+
+ metisForwarder_Destroy(&metis);
+}
+
+// ===================================================================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, metisMessageProcessor_Drop_TestTapNoDrop);
+ LONGBOW_RUN_TEST_CASE(Local, metisMessageProcessor_Drop_TestTapWithDrop);
+ LONGBOW_RUN_TEST_CASE(Local, metisMessageProcessor_Drop_Interest);
+ LONGBOW_RUN_TEST_CASE(Local, metisMessageProcessor_Drop_Object);
+
+ LONGBOW_RUN_TEST_CASE(Local, metisMessageProcessor_ForwardToInterfaceId_NoConnection);
+ LONGBOW_RUN_TEST_CASE(Local, metisMessageProcessor_ForwardToInterfaceId_SendFails);
+ LONGBOW_RUN_TEST_CASE(Local, metisMessageProcessor_ForwardToInterfaceId_SendInterest);
+ LONGBOW_RUN_TEST_CASE(Local, metisMessageProcessor_ForwardToInterfaceId_SendObject);
+
+ LONGBOW_RUN_TEST_CASE(Local, metisMessageProcessor_ForwardToInterfaceId_ZeroHopLimit_Remote);
+ LONGBOW_RUN_TEST_CASE(Local, metisMessageProcessor_ForwardToInterfaceId_ZeroHopLimit_Local);
+
+ LONGBOW_RUN_TEST_CASE(Local, metisMessageProcessor_ForwardToNexthops);
+ LONGBOW_RUN_TEST_CASE(Local, metisMessageProcessor_ForwardToNexthops_DontForwardToIngress);
+
+
+ LONGBOW_RUN_TEST_CASE(Local, metisMessageProcessor_ReceiveContentObjectV0_InPit);
+ LONGBOW_RUN_TEST_CASE(Local, metisMessageProcessor_ReceiveContentObjectV0_NotInPit);
+ LONGBOW_RUN_TEST_CASE(Local, metisMessageProcessor_ReceiveContentObjectV1_InPit);
+ LONGBOW_RUN_TEST_CASE(Local, metisMessageProcessor_ReceiveContentObjectV1_NotInPit);
+
+ LONGBOW_RUN_TEST_CASE(Local, metisMessageProcessor_ReceiveInterest_InPit);
+ LONGBOW_RUN_TEST_CASE(Local, metisMessageProcessor_ReceiveInterest_NotInPit);
+
+ LONGBOW_RUN_TEST_CASE(Local, metisMessageProcessor_ReceiveInterest_InCache);
+ LONGBOW_RUN_TEST_CASE(Local, metisMessageProcessor_ReceiveInterest_InCacheButExpired);
+
+ LONGBOW_RUN_TEST_CASE(Local, metisMessageProcessor_ReceiveInterest_NotInCache);
+ LONGBOW_RUN_TEST_CASE(Local, metisMessageProcessor_ReceiveInterest_InFib);
+ LONGBOW_RUN_TEST_CASE(Local, metisMessageProcessor_ReceiveInterest_NotInFib);
+ LONGBOW_RUN_TEST_CASE(Local, metisMessageProcessor_ReceiveInterest_NoHopLimit);
+
+ LONGBOW_RUN_TEST_CASE(Local, metisMessageProcessor_AggregateInterestInPit_NewEntry);
+ LONGBOW_RUN_TEST_CASE(Local, metisMessageProcessor_AggregateInterestInPit_ExistingEntry);
+
+ LONGBOW_RUN_TEST_CASE(Local, metisMessageProcessor_SatisfyFromContentStore_IsInStore);
+ LONGBOW_RUN_TEST_CASE(Local, metisMessageProcessor_SatisfyFromContentStore_IsNotInStore);
+ LONGBOW_RUN_TEST_CASE(Local, metisMessageProcessor_SatisfyFromContentStore_WithKeyIdNotVerified_WithoutVerification);
+
+ LONGBOW_RUN_TEST_CASE(Local, metisMessageProcessor_ForwardViaFib_IsNotInFib);
+ LONGBOW_RUN_TEST_CASE(Local, metisMessageProcessor_ForwardViaFib_IsInFib_EmptyEgressSet);
+
+ LONGBOW_RUN_TEST_CASE(Local, metisMessageProcessor_CheckAndDecrementHopLimitOnIngress_NoHopLimit);
+ LONGBOW_RUN_TEST_CASE(Local, metisMessageProcessor_CheckAndDecrementHopLimitOnIngress_Local_Zero);
+ LONGBOW_RUN_TEST_CASE(Local, metisMessageProcessor_CheckAndDecrementHopLimitOnIngress_Local_NonZero);
+ LONGBOW_RUN_TEST_CASE(Local, metisMessageProcessor_CheckAndDecrementHopLimitOnIngress_Remote_Zero);
+ LONGBOW_RUN_TEST_CASE(Local, metisMessageProcessor_CheckAndDecrementHopLimitOnIngress_Remote_NonZero);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ memset(&testTap, 0, sizeof(testTap));
+ 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;
+}
+
+/**
+ * Test that the tap does not fire if testTap.callOnDrop is false
+ */
+LONGBOW_TEST_CASE(Local, metisMessageProcessor_Drop_TestTapNoDrop)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 2, logger);
+
+
+ testTap.callOnDrop = false;
+ metisMessageProcessor_AddTap(processor, &testTapTemplate);
+
+ // should not increment a counter
+ metisMessageProcessor_Drop(processor, interest);
+
+ metisMessage_Release(&interest);
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+
+ assertTrue(testTap.onDropCount == 0, "Incorrect onDropCount, expecting %u, got %u", 0, testTap.onDropCount);
+}
+
+/**
+ * Test that the tap does fire if testTap.callOnDrop is true
+ */
+LONGBOW_TEST_CASE(Local, metisMessageProcessor_Drop_TestTapWithDrop)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 2, logger);
+
+
+ testTap.callOnDrop = true;
+ metisMessageProcessor_AddTap(processor, &testTapTemplate);
+
+ // should increment a counter
+ metisMessageProcessor_Drop(processor, interest);
+
+ metisMessage_Release(&interest);
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+
+ assertTrue(testTap.onDropCount == 1, "Incorrect onDropCount, expecting %u, got %u", 1, testTap.onDropCount);
+}
+
+/**
+ * Test that when we drop an interest it is counted
+ */
+LONGBOW_TEST_CASE(Local, metisMessageProcessor_Drop_Interest)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 2, logger);
+
+
+ // should increment a counter
+ metisMessageProcessor_Drop(processor, interest);
+
+ unsigned countDropped = processor->stats.countDropped;
+ unsigned countInterestsDropped = processor->stats.countInterestsDropped;
+
+ metisMessage_Release(&interest);
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+
+ assertTrue(countInterestsDropped == 1, "Incorrect countInterestsDropped, expecting %u, got %u", 1, countInterestsDropped);
+ assertTrue(countDropped == 1, "Incorrect countDropped, expecting %u, got %u", 1, countDropped);
+}
+
+/**
+ * Test that when we drop an object it is counted
+ */
+LONGBOW_TEST_CASE(Local, metisMessageProcessor_Drop_Object)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ MetisMessage *object = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 2, logger);
+
+
+ // should increment a counter
+ metisMessageProcessor_Drop(processor, object);
+
+ unsigned countDropped = processor->stats.countDropped;
+ unsigned countObjectsDropped = processor->stats.countObjectsDropped;
+
+ metisMessage_Release(&object);
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+
+ assertTrue(countObjectsDropped == 1, "Incorrect countInterestsDropped, expecting %u, got %u", 1, countObjectsDropped);
+ assertTrue(countDropped == 1, "Incorrect countDropped, expecting %u, got %u", 1, countDropped);
+}
+
+/**
+ * Send a message to a connection that does not exist in the connection table
+ */
+LONGBOW_TEST_CASE(Local, metisMessageProcessor_ForwardToInterfaceId_NoConnection)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ MetisMessage *object = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 2, logger);
+
+
+ metisMessageProcessor_ForwardToInterfaceId(processor, object, 99);
+
+ uint32_t countDroppedConnectionNotFound = processor->stats.countDroppedConnectionNotFound;
+ uint32_t countObjectsDropped = processor->stats.countObjectsDropped;
+
+ metisMessage_Release(&object);
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+
+ assertTrue(countDroppedConnectionNotFound == 1, "Incorrect countDroppedConnectionNotFound, expecting %u, got %u", 1, countDroppedConnectionNotFound);
+ assertTrue(countObjectsDropped == 1, "Incorrect countDropped, expecting %u, got %u", 1, countObjectsDropped);
+}
+
+/**
+ * Send to a connection that is down
+ */
+LONGBOW_TEST_CASE(Local, metisMessageProcessor_ForwardToInterfaceId_SendFails)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ MetisMessage *object = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 2, logger);
+
+ MetisIoOperations *ops = mockIoOperationsData_CreateSimple(1, 2, 99, false, false, false);
+ MetisConnection *conn = metisConnection_Create(ops);
+
+ metisConnectionTable_Add(metisForwarder_GetConnectionTable(metis), conn);
+ metisMessageProcessor_ForwardToInterfaceId(processor, object, 99);
+
+ uint32_t countSendFailures = processor->stats.countSendFailures;
+ uint32_t countObjectsDropped = processor->stats.countObjectsDropped;
+
+ metisMessage_Release(&object);
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+ mockIoOperationsData_Destroy(&ops);
+
+ assertTrue(countSendFailures == 1, "Incorrect countSendFailures, expecting %u, got %u", 1, countSendFailures);
+ assertTrue(countObjectsDropped == 1, "Incorrect countDropped, expecting %u, got %u", 1, countObjectsDropped);
+}
+
+/**
+ * Send an interest out a good connection
+ */
+LONGBOW_TEST_CASE(Local, metisMessageProcessor_ForwardToInterfaceId_SendInterest)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ MetisMessage *object = metisMessage_CreateFromArray(metisTestDataV0_EncodedInterest, sizeof(metisTestDataV0_EncodedInterest), 1, 2, logger);
+
+ MetisIoOperations *ops = mockIoOperationsData_CreateSimple(1, 2, 99, true, true, false);
+ MockIoOperationsData *data = metisIoOperations_GetClosure(ops);
+ MetisConnection *conn = metisConnection_Create(ops);
+
+ metisConnectionTable_Add(metisForwarder_GetConnectionTable(metis), conn);
+ metisMessageProcessor_ForwardToInterfaceId(processor, object, 99);
+
+ uint32_t countInterestForwarded = processor->stats.countInterestForwarded;
+ uint32_t sendCount = data->sendCount;
+
+ metisMessage_Release(&object);
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+ mockIoOperationsData_Destroy(&ops);
+
+ assertTrue(countInterestForwarded == 1, "Incorrect countInterestForwarded, expecting %u, got %u", 1, countInterestForwarded);
+ assertTrue(sendCount == 1, "Incorrect sendCount, expecting %u, got %u", 1, sendCount);
+}
+
+/**
+ * Send a content object out a good connection
+ */
+LONGBOW_TEST_CASE(Local, metisMessageProcessor_ForwardToInterfaceId_SendObject)
+{
+ // setup
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ MetisMessage *object = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 2, logger);
+
+ MetisIoOperations *ops = mockIoOperationsData_CreateSimple(1, 2, 99, true, true, false);
+ MockIoOperationsData *data = metisIoOperations_GetClosure(ops);
+ MetisConnection *conn = metisConnection_Create(ops);
+
+ // test
+ metisConnectionTable_Add(metisForwarder_GetConnectionTable(metis), conn);
+ metisMessageProcessor_ForwardToInterfaceId(processor, object, 99);
+
+ // measure
+ uint32_t countObjectsForwarded = processor->stats.countObjectsForwarded;
+ uint32_t sendCount = data->sendCount;
+
+ // cleanup
+ metisMessage_Release(&object);
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+ mockIoOperationsData_Destroy(&ops);
+
+ // validate
+ assertTrue(countObjectsForwarded == 1, "Incorrect countObjectsForwarded, expecting %u, got %u", 1, countObjectsForwarded);
+ assertTrue(sendCount == 1, "Incorrect sendCount, expecting %u, got %u", 1, sendCount);
+}
+
+/*
+ * Try to forward an interest with a 0 hop limit to a remote. Should fail
+ */
+LONGBOW_TEST_CASE(Local, metisMessageProcessor_ForwardToInterfaceId_ZeroHopLimit_Remote)
+{
+ // setup
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ MetisMessage *object = metisMessage_CreateFromArray(metisTestDataV0_EncodedInterest_zero_hoplimit, sizeof(metisTestDataV0_EncodedInterest_zero_hoplimit), 1, 2, logger);
+
+
+ unsigned connId = 99;
+ bool isLocal = false;
+ MetisIoOperations *ops = mockIoOperationsData_CreateSimple(1, 2, connId, true, true, isLocal);
+ MockIoOperationsData *data = metisIoOperations_GetClosure(ops);
+ MetisConnection *conn = metisConnection_Create(ops);
+
+ metisConnectionTable_Add(metisForwarder_GetConnectionTable(metis), conn);
+ metisMessageProcessor_ForwardToInterfaceId(processor, object, connId);
+
+ // measure
+ uint32_t countDropZeroToRemote = processor->stats.countDroppedZeroHopLimitToRemote;
+ uint32_t sendCount = data->sendCount;
+
+ // cleanup
+ metisMessage_Release(&object);
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+ mockIoOperationsData_Destroy(&ops);
+
+ // validate
+ assertTrue(countDropZeroToRemote == 1, "Incorrect countDropZeroToRemote, expecting %u, got %u", 1, countDropZeroToRemote);
+ assertTrue(sendCount == 0, "Incorrect sendCount, expecting %u, got %u", 0, sendCount);
+}
+
+/*
+ * Try to forward an interest with a 0 hop limit to a local. Should succeed.
+ */
+LONGBOW_TEST_CASE(Local, metisMessageProcessor_ForwardToInterfaceId_ZeroHopLimit_Local)
+{
+ // setup
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ MetisMessage *object = metisMessage_CreateFromArray(metisTestDataV0_EncodedInterest_zero_hoplimit, sizeof(metisTestDataV0_EncodedInterest_zero_hoplimit), 1, 2, logger);
+
+
+ unsigned connId = 99;
+ bool isLocal = true;
+ MetisIoOperations *ops = mockIoOperationsData_CreateSimple(1, 2, connId, true, true, isLocal);
+ MockIoOperationsData *data = metisIoOperations_GetClosure(ops);
+ MetisConnection *conn = metisConnection_Create(ops);
+
+ metisConnectionTable_Add(metisForwarder_GetConnectionTable(metis), conn);
+ metisMessageProcessor_ForwardToInterfaceId(processor, object, connId);
+
+ // measure
+ uint32_t countDropZeroToRemote = processor->stats.countDroppedZeroHopLimitToRemote;
+ uint32_t sendCount = data->sendCount;
+
+ // cleanup
+ metisMessage_Release(&object);
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+ mockIoOperationsData_Destroy(&ops);
+
+ // validate
+ assertTrue(countDropZeroToRemote == 0, "Incorrect countDropZeroToRemote, expecting %u, got %u", 0, countDropZeroToRemote);
+ assertTrue(sendCount == 1, "Incorrect sendCount, expecting %u, got %u", 1, sendCount);
+}
+
+
+/**
+ * Create 2 connections, and try to forwarder to both of them
+ */
+LONGBOW_TEST_CASE(Local, metisMessageProcessor_ForwardToNexthops)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ MetisMessage *object = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 2, logger);
+
+
+ // 2 connections
+ MetisIoOperations *ops_42 = mockIoOperationsData_CreateSimple(1, 2, 42, true, true, false);
+ MockIoOperationsData *data_42 = metisIoOperations_GetClosure(ops_42);
+ MetisConnection *conn_42 = metisConnection_Create(ops_42);
+
+ MetisIoOperations *ops_43 = mockIoOperationsData_CreateSimple(1, 2, 43, true, true, false);
+ MockIoOperationsData *data_43 = metisIoOperations_GetClosure(ops_43);
+ MetisConnection *conn_43 = metisConnection_Create(ops_43);
+
+ // Add the connections to the connection table
+ metisConnectionTable_Add(metisForwarder_GetConnectionTable(metis), conn_42);
+ metisConnectionTable_Add(metisForwarder_GetConnectionTable(metis), conn_43);
+
+ // Setup the next hops
+ MetisNumberSet *nexthops = metisNumberSet_Create();
+ metisNumberSet_Add(nexthops, 42);
+ metisNumberSet_Add(nexthops, 43);
+
+ // forward the content object to both of them
+ metisMessageProcessor_ForwardToNexthops(processor, object, nexthops);
+
+ // there should be 2 object forwards and each IoOps should have gotten 1 send
+ uint32_t countObjectsForwarded = processor->stats.countObjectsForwarded;
+ uint32_t sendCount_42 = data_42->sendCount;
+ uint32_t sendCount_43 = data_43->sendCount;
+
+ // cleanup
+ metisNumberSet_Release(&nexthops);
+ metisMessage_Release(&object);
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+ mockIoOperationsData_Destroy(&ops_42);
+ mockIoOperationsData_Destroy(&ops_43);
+
+ // validate
+ assertTrue(countObjectsForwarded == 2, "Incorrect countObjectsForwarded, expecting %u, got %u", 2, countObjectsForwarded);
+ assertTrue(sendCount_42 == 1, "Incorrect sendCount_42, expecting %u, got %u", 1, sendCount_42);
+ assertTrue(sendCount_43 == 1, "Incorrect sendCount_43, expecting %u, got %u", 1, sendCount_43);
+}
+
+/**
+ * There is a route in the FIB that points to the ingress interface of an interest.
+ * Ensure that we don't forward to that interface
+ */
+LONGBOW_TEST_CASE(Local, metisMessageProcessor_ForwardToNexthops_DontForwardToIngress)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+
+ // ingress interface is #42, so it should not get forwarded out there
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ MetisMessage *object = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 42, 1, logger);
+
+
+ // 2 connections
+ MetisIoOperations *ops_42 = mockIoOperationsData_CreateSimple(1, 2, 42, true, true, false);
+ MockIoOperationsData *data_42 = metisIoOperations_GetClosure(ops_42);
+ MetisConnection *conn_42 = metisConnection_Create(ops_42);
+
+ MetisIoOperations *ops_43 = mockIoOperationsData_CreateSimple(1, 2, 43, true, true, false);
+ MockIoOperationsData *data_43 = metisIoOperations_GetClosure(ops_43);
+ MetisConnection *conn_43 = metisConnection_Create(ops_43);
+
+ // Add the connections to the connection table
+ metisConnectionTable_Add(metisForwarder_GetConnectionTable(metis), conn_42);
+ metisConnectionTable_Add(metisForwarder_GetConnectionTable(metis), conn_43);
+
+ // Setup the next hops
+ MetisNumberSet *nexthops = metisNumberSet_Create();
+ metisNumberSet_Add(nexthops, 42);
+ metisNumberSet_Add(nexthops, 43);
+
+ // forward the content object to both of them
+ metisMessageProcessor_ForwardToNexthops(processor, object, nexthops);
+
+ // there should be 2 object forwards and each IoOps should have gotten 1 send
+ uint32_t countObjectsForwarded = processor->stats.countObjectsForwarded;
+ uint32_t sendCount_42 = data_42->sendCount;
+ uint32_t sendCount_43 = data_43->sendCount;
+
+ // cleanup
+ metisNumberSet_Release(&nexthops);
+ metisMessage_Release(&object);
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+ mockIoOperationsData_Destroy(&ops_42);
+ mockIoOperationsData_Destroy(&ops_43);
+
+ // validate
+ assertTrue(countObjectsForwarded == 1, "Incorrect countObjectsForwarded, expecting %u, got %u", 1, countObjectsForwarded);
+ assertTrue(sendCount_42 == 0, "Incorrect sendCount_42, expecting %u, got %u", 0, sendCount_42);
+ assertTrue(sendCount_43 == 1, "Incorrect sendCount_43, expecting %u, got %u", 1, sendCount_43);
+}
+
+LONGBOW_TEST_CASE(Local, metisMessageProcessor_ReceiveContentObjectV0_InPit)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 2, logger);
+ MetisMessage *object = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 3, 4, logger);
+
+
+ // receive the interst to add it to PIT
+ metisMessageProcessor_ReceiveInterest(processor, interest);
+
+ // now test the function and measure results
+ // There is no actual connection "1" (the interest ingress port), so the forwarding
+ // will show up as a countDroppedConnectionNotFound.
+
+ uint32_t beforeCountDroppedConnectionNotFound = processor->stats.countDroppedConnectionNotFound;
+ metisMessageProcessor_ReceiveContentObject(processor, object);
+ uint32_t afterCountDroppedConnectionNotFound = processor->stats.countDroppedConnectionNotFound;
+
+ // cleanup
+ metisMessage_Release(&interest);
+ metisMessage_Release(&object);
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+
+ // validate
+ assertTrue(afterCountDroppedConnectionNotFound == beforeCountDroppedConnectionNotFound + 1,
+ "Incorrect afterCountDroppedConnectionNotFound, expected %u got %u",
+ beforeCountDroppedConnectionNotFound + 1,
+ afterCountDroppedConnectionNotFound);
+}
+
+LONGBOW_TEST_CASE(Local, metisMessageProcessor_ReceiveContentObjectV0_NotInPit)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ MetisMessage *object = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 2, logger);
+
+
+ // now test the function and measure results
+ uint32_t beforeCountDroppedNoReversePath = processor->stats.countDroppedNoReversePath;
+ metisMessageProcessor_ReceiveContentObject(processor, object);
+ uint32_t afterCountDroppedNoReversePath = processor->stats.countDroppedNoReversePath;
+
+ // cleanup
+ metisMessage_Release(&object);
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+
+ // validate
+ assertTrue(afterCountDroppedNoReversePath == beforeCountDroppedNoReversePath + 1,
+ "Incorrect afterCountDroppedNoReversePath, expected %u got %u",
+ beforeCountDroppedNoReversePath + 1,
+ afterCountDroppedNoReversePath);
+}
+
+LONGBOW_TEST_CASE(Local, metisMessageProcessor_ReceiveContentObjectV1_InPit)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+// metisLogger_SetLogLevel(logger, MetisLoggerFacility_Message, PARCLogLevel_Debug);
+// metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV1_Interest_NameA_Crc32c, sizeof(metisTestDataV1_Interest_NameA_Crc32c), 1, 2, logger);
+ MetisMessage *object = metisMessage_CreateFromArray(metisTestDataV1_ContentObject_NameA_Crc32c, sizeof(metisTestDataV1_ContentObject_NameA_Crc32c), 3, 4, logger);
+
+ // receive the interst to add it to PIT
+ metisMessageProcessor_ReceiveInterest(processor, interest);
+
+ // now test the function and measure results
+ // There is no actual connection "1" (the interest ingress port), so the forwarding
+ // will show up as a countDroppedConnectionNotFound.
+
+ uint32_t beforeCountDroppedConnectionNotFound = processor->stats.countDroppedConnectionNotFound;
+ metisMessageProcessor_ReceiveContentObject(processor, object);
+ uint32_t afterCountDroppedConnectionNotFound = processor->stats.countDroppedConnectionNotFound;
+
+ // cleanup
+ metisMessage_Release(&interest);
+ metisMessage_Release(&object);
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+
+ // validate
+ assertTrue(afterCountDroppedConnectionNotFound == beforeCountDroppedConnectionNotFound + 1,
+ "Incorrect afterCountDroppedConnectionNotFound, expected %u got %u",
+ beforeCountDroppedConnectionNotFound + 1,
+ afterCountDroppedConnectionNotFound);
+}
+
+LONGBOW_TEST_CASE(Local, metisMessageProcessor_ReceiveContentObjectV1_NotInPit)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ MetisMessage *object = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 2, logger);
+
+
+ // now test the function and measure results
+ uint32_t beforeCountDroppedNoReversePath = processor->stats.countDroppedNoReversePath;
+ metisMessageProcessor_ReceiveContentObject(processor, object);
+ uint32_t afterCountDroppedNoReversePath = processor->stats.countDroppedNoReversePath;
+
+ // cleanup
+ metisMessage_Release(&object);
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+
+ // validate
+ assertTrue(afterCountDroppedNoReversePath == beforeCountDroppedNoReversePath + 1,
+ "Incorrect afterCountDroppedNoReversePath, expected %u got %u",
+ beforeCountDroppedNoReversePath + 1,
+ afterCountDroppedNoReversePath);
+}
+
+
+/**
+ * There's already a detailed test for this, we just check the stats counter
+ * to make sure the right logic flow is executed. The second interest must come from
+ * a different reverse path to be aggregated.
+ */
+LONGBOW_TEST_CASE(Local, metisMessageProcessor_ReceiveInterest_InPit)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ MetisMessage *interest1 = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 2, logger);
+ MetisMessage *interest2 = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 2, 2, logger);
+
+
+ // add it once
+ metisMessageProcessor_AggregateInterestInPit(processor, interest1);
+
+ // now test the function and measure results
+ uint32_t beforeCountInterestsAggregated = processor->stats.countInterestsAggregated;
+ metisMessageProcessor_ReceiveInterest(processor, interest2);
+ uint32_t afterCountInterestsAggregated = processor->stats.countInterestsAggregated;
+
+ // cleanup
+ metisMessage_Release(&interest1);
+ metisMessage_Release(&interest2);
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+
+ // validate
+ assertTrue(afterCountInterestsAggregated == beforeCountInterestsAggregated + 1,
+ "Incorrect afterCountInterestsAggregated, expected %u got %u",
+ beforeCountInterestsAggregated + 1,
+ afterCountInterestsAggregated);
+}
+
+/**
+ * There's already a detailed test for this, we just check the stats counter
+ * to make sure the right logic flow is executed
+ */
+LONGBOW_TEST_CASE(Local, metisMessageProcessor_ReceiveInterest_NotInPit)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 2, logger);
+
+
+ // now test the function and measure results
+ uint32_t beforeCountInterestsAggregated = processor->stats.countInterestsAggregated;
+ metisMessageProcessor_ReceiveInterest(processor, interest);
+ uint32_t afterCountInterestsAggregated = processor->stats.countInterestsAggregated;
+
+ // also check its in the PIT now
+ MetisPitEntry *pitEntry = metisPIT_GetPitEntry(processor->pit, interest);
+ bool foundInPit = false;
+ if (pitEntry) {
+ foundInPit = true;
+ }
+
+ // cleanup
+ metisPitEntry_Release(&pitEntry);
+ metisMessage_Release(&interest);
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+
+ // validate
+ assertTrue(afterCountInterestsAggregated == beforeCountInterestsAggregated,
+ "Incorrect afterCountInterestsAggregated, expected %u got %u",
+ beforeCountInterestsAggregated,
+ afterCountInterestsAggregated);
+
+ assertTrue(foundInPit, "Did not find interest in the PIT");
+}
+
+/**
+ * There's already a detailed test for this, we just check the stats counter
+ * to make sure the right logic flow is executed
+ */
+LONGBOW_TEST_CASE(Local, metisMessageProcessor_ReceiveInterest_InCache)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 2, logger);
+ MetisMessage *object = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 4, 5, logger);
+
+ // add it to the cache
+ metisContentStoreInterface_PutContent(processor->contentStore, object, 0l);
+
+ // now test the function and measure results
+ uint32_t beforeCountObjectsForwardedFromStore = processor->stats.countInterestsSatisfiedFromStore;
+ metisMessageProcessor_ReceiveInterest(processor, interest);
+ uint32_t afterCountObjectsForwardedFromStore = processor->stats.countInterestsSatisfiedFromStore;
+
+ // cleanup
+ metisMessage_Release(&object);
+ metisMessage_Release(&interest);
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+
+ // validate
+ assertTrue(afterCountObjectsForwardedFromStore == beforeCountObjectsForwardedFromStore + 1,
+ "Incorrect afterCountObjectsForwardedFromStore, expected %u got %u",
+ beforeCountObjectsForwardedFromStore + 1,
+ afterCountObjectsForwardedFromStore);
+}
+
+LONGBOW_TEST_CASE(Local, metisMessageProcessor_ReceiveInterest_InCacheButExpired)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+
+ uint64_t currentTimeInTicks = metisForwarder_GetTicks(processor->metis);
+
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName,
+ sizeof(metisTestDataV0_InterestWithName), 1, currentTimeInTicks, logger);
+ MetisMessage *object = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject,
+ sizeof(metisTestDataV0_EncodedObject), 4, currentTimeInTicks, logger);
+
+ // add it to the cache. It's already expired, so should not be forwarded.
+ metisMessage_SetExpiryTimeTicks(object, currentTimeInTicks + 1000ULL);
+ metisContentStoreInterface_PutContent(processor->contentStore, object, currentTimeInTicks);
+
+ // Crank metis clock.
+ metis->clockOffset = metisForwarder_NanosToTicks(5000000000ULL); // Add 5 seconds. Content is now expired.
+
+ // now test the function and measure results.
+ uint32_t beforeCountObjectsForwardedFromStore = processor->stats.countInterestsSatisfiedFromStore;
+ metisMessageProcessor_ReceiveInterest(processor, interest);
+ uint32_t afterCountObjectsForwardedFromStore = processor->stats.countInterestsSatisfiedFromStore;
+
+ // cleanup
+ metisMessage_Release(&object);
+ metisMessage_Release(&interest);
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+
+ // validate. Nothing should have been forwarded.
+ assertTrue(afterCountObjectsForwardedFromStore == beforeCountObjectsForwardedFromStore,
+ "Incorrect afterCountObjectsForwardedFromStore, expected %u got %u",
+ beforeCountObjectsForwardedFromStore,
+ afterCountObjectsForwardedFromStore);
+}
+
+
+/**
+ * There's already a detailed test for this, we just check the stats counter
+ * to make sure the right logic flow is executed
+ */
+LONGBOW_TEST_CASE(Local, metisMessageProcessor_ReceiveInterest_NotInCache)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 2, logger);
+ MetisMessage *object = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 4, 5, logger);
+
+
+ // now test the function and measure results
+ uint32_t beforeCountObjectsForwardedFromStore = processor->stats.countInterestsSatisfiedFromStore;
+ metisMessageProcessor_ReceiveInterest(processor, interest);
+ uint32_t afterCountObjectsForwardedFromStore = processor->stats.countInterestsSatisfiedFromStore;
+
+ // cleanup
+ metisMessage_Release(&object);
+ metisMessage_Release(&interest);
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+
+ // validate
+ assertTrue(afterCountObjectsForwardedFromStore == beforeCountObjectsForwardedFromStore,
+ "Incorrect afterCountObjectsForwardedFromStore, expected %u got %u",
+ beforeCountObjectsForwardedFromStore,
+ afterCountObjectsForwardedFromStore);
+}
+
+/**
+ * There's already a detailed test for this, we just check the stats counter
+ * to make sure the right logic flow is executed
+ */
+LONGBOW_TEST_CASE(Local, metisMessageProcessor_ReceiveInterest_InFib)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 2, logger);
+
+
+ // ----- Add Route
+ CCNxName *ccnxNameToAdd =
+ ccnxName_CreateFromCString("lci:/2=hello/0xF000=ouch");
+ unsigned interfaceIndex_1 = 22;
+ CPIAddress *nexthop = NULL;
+ struct timeval *lifetime = NULL;
+ unsigned cost = 12;
+ CPIRouteEntry *routeAdd = cpiRouteEntry_Create(ccnxNameToAdd,
+ interfaceIndex_1,
+ nexthop,
+ cpiNameRouteProtocolType_STATIC,
+ cpiNameRouteType_LONGEST_MATCH,
+ lifetime,
+ cost);
+ metisFIB_AddOrUpdate(processor->fib, routeAdd, "random");
+
+ // now test the function and measure results
+ // We will see it in countDroppedConnectionNotFound, because we didnt mock up the interface 22 connection
+ uint32_t beforeCountDroppedConnectionNotFound = processor->stats.countDroppedConnectionNotFound;
+ metisMessageProcessor_ReceiveInterest(processor, interest);
+ uint32_t afterCountDroppedConnectionNotFound = processor->stats.countDroppedConnectionNotFound;
+
+ // cleanup
+ cpiRouteEntry_Destroy(&routeAdd);
+ metisMessage_Release(&interest);
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+
+ // validate
+ assertTrue(afterCountDroppedConnectionNotFound == beforeCountDroppedConnectionNotFound + 1,
+ "Incorrect afterCountDroppedConnectionNotFound, expected %u got %u",
+ beforeCountDroppedConnectionNotFound + 1,
+ afterCountDroppedConnectionNotFound);
+}
+
+/**
+ * There's already a detailed test for this, we just check the stats counter
+ * to make sure the right logic flow is executed
+ */
+LONGBOW_TEST_CASE(Local, metisMessageProcessor_ReceiveInterest_NotInFib)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Local, metisMessageProcessor_ReceiveInterest_NoHopLimit)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_EncodedInterest_no_hoplimit,
+ sizeof(metisTestDataV0_EncodedInterest_no_hoplimit), 1, 2, logger);
+
+
+ metisMessageProcessor_ReceiveInterest(processor, interest);
+ uint32_t dropCount = processor->stats.countDroppedNoHopLimit;
+
+ // cleanup
+ metisMessage_Release(&interest);
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+
+ // validate
+ assertTrue(dropCount == 1,
+ "Incorrect countDroppedNoHopLimit, expected %u got %u",
+ 1,
+ dropCount);
+}
+
+/**
+ * Add an interest to the PIT when it does not exist. Should not increment the "stats.countInterestsAggregated' counter
+ * and should return FALSE, meaning not aggregated
+ */
+LONGBOW_TEST_CASE(Local, metisMessageProcessor_AggregateInterestInPit_NewEntry)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 2, logger);
+
+
+ uint32_t beforeCountInterestsAggregated = processor->stats.countInterestsAggregated;
+ bool aggregated = metisMessageProcessor_AggregateInterestInPit(processor, interest);
+ uint32_t afterCountInterestsAggregated = processor->stats.countInterestsAggregated;
+
+ metisMessage_Release(&interest);
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+
+ assertTrue(afterCountInterestsAggregated == beforeCountInterestsAggregated,
+ "Incorrect afterCountInterestsAggregated, expected %u got %u",
+ beforeCountInterestsAggregated,
+ afterCountInterestsAggregated);
+ assertFalse(aggregated, "Interest aggregated when no interests in table!");
+}
+
+/**
+ * Add an interest to the PIT, then add it again. SHould increment the "stats.countInterestsAggregated" counter and
+ * should return TRUE meaning, it was aggregated. The second interest needs to come from a different interface.
+ */
+LONGBOW_TEST_CASE(Local, metisMessageProcessor_AggregateInterestInPit_ExistingEntry)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ MetisMessage *interest1 = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 2, logger);
+ MetisMessage *interest2 = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 2, 2, logger);
+
+
+ // add it once
+ metisMessageProcessor_AggregateInterestInPit(processor, interest1);
+
+ // now add it again
+ uint32_t beforeCountInterestsAggregated = processor->stats.countInterestsAggregated;
+ bool aggregated = metisMessageProcessor_AggregateInterestInPit(processor, interest2);
+ uint32_t afterCountInterestsAggregated = processor->stats.countInterestsAggregated;
+
+ metisMessage_Release(&interest1);
+ metisMessage_Release(&interest2);
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+
+ assertTrue(afterCountInterestsAggregated == beforeCountInterestsAggregated + 1,
+ "Incorrect afterCountInterestsAggregated, expected %u got %u",
+ beforeCountInterestsAggregated + 1,
+ afterCountInterestsAggregated);
+ assertTrue(aggregated, "Interest not aggregated with self!");
+}
+
+LONGBOW_TEST_CASE(Local, metisMessageProcessor_SatisfyFromContentStore_WithKeyIdNotVerified_WithoutVerification)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+
+ MetisMessage *contentObjectWithKeyId =
+ metisMessage_CreateFromArray(metisTestDataV1_ContentObject_NameA_KeyId1_RsaSha256,
+ sizeof(metisTestDataV1_ContentObject_NameA_KeyId1_RsaSha256), 4, 5, logger);
+
+ // add it to the cache
+ metisContentStoreInterface_PutContent(processor->contentStore, contentObjectWithKeyId, 1l);
+
+ // Now create an Interest with the same name and a KeyId.
+ MetisMessage *interestWithKeyIdRestriction =
+ metisMessage_CreateFromArray(metisTestDataV1_Interest_NameAAndKeyId,
+ sizeof(metisTestDataV1_Interest_NameAAndKeyId), 4, 5, logger);
+
+ // Now test the code. We should NOT match it, due to the content store not currently verifying keyIds.
+ bool success = _satisfyFromContentStore(processor, interestWithKeyIdRestriction);
+ unsigned countObjectsForwardedFromStore = processor->stats.countInterestsSatisfiedFromStore;
+
+ // cleanup
+ metisMessage_Release(&interestWithKeyIdRestriction);
+ metisMessage_Release(&contentObjectWithKeyId);
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+
+ // validate
+ assertFalse(success, "Expected Interest to not be satisfied from cache!");
+ assertTrue(countObjectsForwardedFromStore == 0,
+ "Incorrect countObjectsForwardedFromStore, expected %u got %u",
+ 0,
+ countObjectsForwardedFromStore);
+}
+
+LONGBOW_TEST_CASE(Local, metisMessageProcessor_SatisfyFromContentStore_IsInStore)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 2, logger);
+ MetisMessage *object = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 4, 5, logger);
+
+ // add it to the cache
+ metisContentStoreInterface_PutContent(processor->contentStore, object, 1l);
+
+ // now test the code
+ bool success = _satisfyFromContentStore(processor, interest);
+ unsigned countObjectsForwardedFromStore = processor->stats.countInterestsSatisfiedFromStore;
+
+ // cleanup
+ metisMessage_Release(&interest);
+ metisMessage_Release(&object);
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+
+ // validate
+ assertTrue(success, "Interest not satisfied from cache!");
+ assertTrue(countObjectsForwardedFromStore == 1,
+ "Incorrect countObjectsForwardedFromStore, expected %u got %u",
+ 1,
+ countObjectsForwardedFromStore);
+}
+
+LONGBOW_TEST_CASE(Local, metisMessageProcessor_SatisfyFromContentStore_IsNotInStore)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 2, logger);
+ MetisMessage *object = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 4, 5, logger);
+
+
+ // don't add it to the cache
+
+ // now test the code
+ bool success = _satisfyFromContentStore(processor, interest);
+ unsigned countObjectsForwardedFromStore = processor->stats.countInterestsSatisfiedFromStore;
+
+ // cleanup
+ metisMessage_Release(&interest);
+ metisMessage_Release(&object);
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+
+ // validate
+ assertFalse(success, "Interest satisfied from cache, when we didn't put it there!");
+ assertTrue(countObjectsForwardedFromStore == 0,
+ "Incorrect countObjectsForwardedFromStore, expected %u got %u",
+ 0,
+ countObjectsForwardedFromStore);
+}
+
+/**
+ * Add fib entry /hello/ouch and ask for /party/ouch
+ */
+LONGBOW_TEST_CASE(Local, metisMessageProcessor_ForwardViaFib_IsNotInFib)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+
+ // ----- Add
+ CCNxName *ccnxNameToAdd =
+ ccnxName_CreateFromCString("lci:/2=hello/0xF000=ouch");
+
+ unsigned interfaceIndex_1 = 22;
+ CPIAddress *nexthop = NULL;
+ struct timeval *lifetime = NULL;
+ unsigned cost = 12;
+ CPIRouteEntry *routeAdd = cpiRouteEntry_Create(ccnxNameToAdd, interfaceIndex_1, nexthop,
+ cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, lifetime, cost);
+ metisFIB_AddOrUpdate(processor->fib, routeAdd,"random" );
+
+ // ----- Measure
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithOtherName, sizeof(metisTestDataV0_InterestWithOtherName), 1, 2, logger);
+
+
+ bool success = metisMessageProcessor_ForwardViaFib(processor, interest);
+
+ // ----- Cleanup
+ cpiRouteEntry_Destroy(&routeAdd);
+ metisMessage_Release(&interest);
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+
+ // ----- Validate
+ assertFalse(success, "Returned true even though no route");
+}
+
+/**
+ * Forward to an existing FIB entry. The PIT entry has an empty egress set.
+ */
+LONGBOW_TEST_CASE(Local, metisMessageProcessor_ForwardViaFib_IsInFib_EmptyEgressSet)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+
+ // ----- Add Route
+ CCNxName *ccnxNameToAdd =
+ ccnxName_CreateFromCString("lci:/2=hello/0xF000=ouch");
+ unsigned interfaceIndex_1 = 22;
+ CPIAddress *nexthop = NULL;
+ struct timeval *lifetime = NULL;
+ unsigned cost = 12;
+ CPIRouteEntry *routeAdd = cpiRouteEntry_Create(ccnxNameToAdd, interfaceIndex_1, nexthop,
+ cpiNameRouteProtocolType_STATIC, cpiNameRouteType_LONGEST_MATCH, lifetime, cost);
+ metisFIB_AddOrUpdate(processor->fib, routeAdd, "random");
+
+ // ----- Add PIT entry
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 2, logger);
+
+
+ metisPIT_ReceiveInterest(processor->pit, interest);
+
+ // ----- Measure
+ bool success = metisMessageProcessor_ForwardViaFib(processor, interest);
+
+ // ----- Cleanup
+ cpiRouteEntry_Destroy(&routeAdd);
+ metisMessage_Release(&interest);
+ metisMessageProcessor_Destroy(&processor);
+ metisForwarder_Destroy(&metis);
+
+ // ----- Validate
+ assertTrue(success, "Returned false with existing PIT entry");
+}
+
+MetisConnection *
+setupMockConnection(MetisForwarder *metis, bool isLocal)
+{
+ MetisIoOperations *ops = mockIoOperationsData_CreateSimple(1, 2, 99, false, false, isLocal);
+ MetisConnection *conn = metisConnection_Create(ops);
+ metisConnectionTable_Add(metisForwarder_GetConnectionTable(metis), conn);
+
+ return conn;
+}
+
+LONGBOW_TEST_CASE(Local, metisMessageProcessor_CheckAndDecrementHopLimitOnIngress_NoHopLimit)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+
+ bool isLocal = false;
+ MetisConnection *conn = setupMockConnection(metis, isLocal);
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ MetisMessage *interest =
+ metisMessage_CreateFromArray(metisTestDataV0_EncodedInterest_no_hoplimit,
+ sizeof(metisTestDataV0_EncodedInterest_no_hoplimit), metisConnection_GetConnectionId(conn), 2, logger);
+
+
+ bool success = metisMessageProcessor_CheckAndDecrementHopLimitOnIngress(processor, interest);
+ assertFalse(success, "Should have failed for an interest without hoplimit");
+
+ assertTrue(processor->stats.countDroppedNoHopLimit == 1,
+ "Wrong countDroppedNoHopLimit, got %u expected %u", processor->stats.countDroppedNoHopLimit, 1);
+ assertTrue(processor->stats.countDroppedZeroHopLimitFromRemote == 0,
+ "Wrong countDroppedZeroHopLimitFromRemote, got %u expected %u", processor->stats.countDroppedZeroHopLimitFromRemote, 0);
+
+ metisMessage_Release(&interest);
+ metisMessageProcessor_Destroy(&processor);
+ MetisIoOperations *ioOps = metisConnection_GetIoOperations(conn);
+ metisForwarder_Destroy(&metis);
+ mockIoOperationsData_Destroy(&ioOps);
+}
+
+LONGBOW_TEST_CASE(Local, metisMessageProcessor_CheckAndDecrementHopLimitOnIngress_Local_Zero)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+
+ bool isLocal = true;
+ MetisConnection *conn = setupMockConnection(metis, isLocal);
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ MetisMessage *interest =
+ metisMessage_CreateFromArray(metisTestDataV0_EncodedInterest_zero_hoplimit,
+ sizeof(metisTestDataV0_EncodedInterest_zero_hoplimit), metisConnection_GetConnectionId(conn), 2, logger);
+
+
+ bool success = metisMessageProcessor_CheckAndDecrementHopLimitOnIngress(processor, interest);
+ assertTrue(success, "Local with 0 hoplimit should have been ok");
+ assertTrue(processor->stats.countDroppedNoHopLimit == 0,
+ "Wrong countDroppedNoHopLimit, got %u expected %u", processor->stats.countDroppedNoHopLimit, 0);
+ assertTrue(processor->stats.countDroppedZeroHopLimitFromRemote == 0,
+ "Wrong countDroppedZeroHopLimitFromRemote, got %u expected %u", processor->stats.countDroppedZeroHopLimitFromRemote, 0);
+
+ metisMessage_Release(&interest);
+ metisMessageProcessor_Destroy(&processor);
+ MetisIoOperations *ioOps = metisConnection_GetIoOperations(conn);
+ metisForwarder_Destroy(&metis);
+ mockIoOperationsData_Destroy(&ioOps);
+}
+
+LONGBOW_TEST_CASE(Local, metisMessageProcessor_CheckAndDecrementHopLimitOnIngress_Local_NonZero)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+
+ bool isLocal = true;
+ MetisConnection *conn = setupMockConnection(metis, isLocal);
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ MetisMessage *interest =
+ metisMessage_CreateFromArray(metisTestDataV0_EncodedInterest,
+ sizeof(metisTestDataV0_EncodedInterest), metisConnection_GetConnectionId(conn), 2, logger);
+
+
+ bool success = metisMessageProcessor_CheckAndDecrementHopLimitOnIngress(processor, interest);
+ assertTrue(success, "Local with non-0 hoplimit should have been ok");
+ assertTrue(processor->stats.countDroppedNoHopLimit == 0,
+ "Wrong countDroppedNoHopLimit, got %u expected %u", processor->stats.countDroppedNoHopLimit, 0);
+ assertTrue(processor->stats.countDroppedZeroHopLimitFromRemote == 0,
+ "Wrong countDroppedZeroHopLimitFromRemote, got %u expected %u", processor->stats.countDroppedZeroHopLimitFromRemote, 0);
+
+ metisMessage_Release(&interest);
+ metisMessageProcessor_Destroy(&processor);
+ MetisIoOperations *ioOps = metisConnection_GetIoOperations(conn);
+ metisForwarder_Destroy(&metis);
+ mockIoOperationsData_Destroy(&ioOps);
+}
+
+LONGBOW_TEST_CASE(Local, metisMessageProcessor_CheckAndDecrementHopLimitOnIngress_Remote_Zero)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+
+ bool isLocal = false;
+ MetisConnection *conn = setupMockConnection(metis, isLocal);
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ MetisMessage *interest =
+ metisMessage_CreateFromArray(metisTestDataV0_EncodedInterest_zero_hoplimit,
+ sizeof(metisTestDataV0_EncodedInterest_zero_hoplimit), metisConnection_GetConnectionId(conn), 2, logger);
+
+
+ bool success = metisMessageProcessor_CheckAndDecrementHopLimitOnIngress(processor, interest);
+ assertFalse(success, "Remote with 0 hoplimit should have been failure");
+ assertTrue(processor->stats.countDroppedNoHopLimit == 0,
+ "Wrong countDroppedNoHopLimit, got %u expected %u", processor->stats.countDroppedNoHopLimit, 0);
+ assertTrue(processor->stats.countDroppedZeroHopLimitFromRemote == 1,
+ "Wrong countDroppedZeroHopLimitFromRemote, got %u expected %u", processor->stats.countDroppedZeroHopLimitFromRemote, 1);
+
+ metisMessage_Release(&interest);
+ metisMessageProcessor_Destroy(&processor);
+ MetisIoOperations *ioOps = metisConnection_GetIoOperations(conn);
+ metisForwarder_Destroy(&metis);
+ mockIoOperationsData_Destroy(&ioOps);
+}
+
+LONGBOW_TEST_CASE(Local, metisMessageProcessor_CheckAndDecrementHopLimitOnIngress_Remote_NonZero)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisMessageProcessor *processor = metisMessageProcessor_Create(metis);
+
+ bool isLocal = false;
+ MetisConnection *conn = setupMockConnection(metis, isLocal);
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ MetisMessage *interest =
+ metisMessage_CreateFromArray(metisTestDataV0_EncodedInterest, sizeof(metisTestDataV0_EncodedInterest), metisConnection_GetConnectionId(conn), 2, logger);
+
+
+ bool success = metisMessageProcessor_CheckAndDecrementHopLimitOnIngress(processor, interest);
+ assertTrue(success, "Remote with non-0 hoplimit should have been ok");
+ assertTrue(processor->stats.countDroppedNoHopLimit == 0,
+ "Wrong countDroppedNoHopLimit, got %u expected %u", processor->stats.countDroppedNoHopLimit, 0);
+ assertTrue(processor->stats.countDroppedZeroHopLimitFromRemote == 0,
+ "Wrong countDroppedZeroHopLimitFromRemote, got %u expected %u", processor->stats.countDroppedZeroHopLimitFromRemote, 0);
+
+ metisMessage_Release(&interest);
+ metisMessageProcessor_Destroy(&processor);
+ MetisIoOperations *ioOps = metisConnection_GetIoOperations(conn);
+ metisForwarder_Destroy(&metis);
+ mockIoOperationsData_Destroy(&ioOps);
+}
+
+
+// ========================================================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metis_MessageProcessor);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/metis/ccnx/forwarder/metis/processor/test/test_metis_PIT.c b/metis/ccnx/forwarder/metis/processor/test/test_metis_PIT.c
new file mode 100644
index 00000000..90403402
--- /dev/null
+++ b/metis/ccnx/forwarder/metis/processor/test/test_metis_PIT.c
@@ -0,0 +1,223 @@
+/*
+ * 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 tests were written before MetisMatchRulesTable was broken out of the PIT.
+ * So, many of the tests "cheat" by looking directly in a constiuent table in MetisMatchingRulesTable.
+ * They should be re-written to use the MetisMatchingRulesTable API.
+ */
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../metis_PIT.c"
+
+
+
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/logging/parc_LogReporterTextStdout.h>
+
+#include <parc/logging/parc_LogReporterTextStdout.h>
+
+// ===============================================================================================
+// Mock PIT
+// These functions just count calls. The Destroy interface does not actually release memeory, you
+// need to call _metisPIT_Release() yourself -- note that this is a static function with leading "_".
+
+typedef struct mock_pit {
+ unsigned countRelease;
+ unsigned countReceiveInterest;
+ unsigned countSatisfyInterest;
+ unsigned countRemoveInterest;
+ unsigned countGetPitEntry;
+} _MockPIT;
+
+static void
+_mockPITInterface_Release(MetisPIT **pitPtr)
+{
+ _MockPIT *mock = metisPIT_Closure(*pitPtr);
+ mock->countRelease++;
+ *pitPtr = NULL;
+}
+
+static MetisPITVerdict
+_mockPITInterface_ReceiveInterest(MetisPIT *pit, MetisMessage *interestMessage)
+{
+ _MockPIT *mock = metisPIT_Closure(pit);
+ mock->countReceiveInterest++;
+ return MetisPITVerdict_Aggregate;
+}
+
+static MetisNumberSet *
+_mockPITInterface_SatisfyInterest(MetisPIT *pit, const MetisMessage *objectMessage)
+{
+ _MockPIT *mock = metisPIT_Closure(pit);
+ mock->countSatisfyInterest++;
+ return NULL;
+}
+
+static void
+_mockPITInterface_RemoveInterest(MetisPIT *pit, const MetisMessage *interestMessage)
+{
+ _MockPIT *mock = metisPIT_Closure(pit);
+ mock->countRemoveInterest++;
+}
+
+static MetisPitEntry *
+_mockPITInterface_GetPitEntry(const MetisPIT *pit, const MetisMessage *interestMessage)
+{
+ _MockPIT *mock = metisPIT_Closure(pit);
+ mock->countGetPitEntry++;
+ return NULL;
+}
+
+static MetisPIT *
+_mockPIT_Create(void)
+{
+ size_t allocation = sizeof(MetisPIT) + sizeof(_MockPIT);
+ MetisPIT *pit = parcMemory_AllocateAndClear(allocation);
+
+ pit->getPitEntry = _mockPITInterface_GetPitEntry;
+ pit->receiveInterest = _mockPITInterface_ReceiveInterest;
+ pit->release = _mockPITInterface_Release;
+ pit->removeInterest = _mockPITInterface_RemoveInterest;
+ pit->satisfyInterest = _mockPITInterface_SatisfyInterest;
+
+ pit->closure = (uint8_t *) pit + sizeof(MetisPIT);
+ return pit;
+}
+
+static void
+_metisPIT_Release(MetisPIT **pitPtr)
+{
+ parcMemory_Deallocate(pitPtr);
+}
+
+
+// ===============================================================================================
+
+LONGBOW_TEST_RUNNER(metis_PIT)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(metis_PIT)
+{
+ 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_PIT)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ===============================================================================================
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, metisPIT_Closure);
+ LONGBOW_RUN_TEST_CASE(Global, metisPIT_Release);
+ LONGBOW_RUN_TEST_CASE(Global, metisPIT_ReceiveInterest);
+ LONGBOW_RUN_TEST_CASE(Global, metisPIT_SatisfyInterest);
+ LONGBOW_RUN_TEST_CASE(Global, metisPIT_RemoveInterest);
+ LONGBOW_RUN_TEST_CASE(Global, metisPIT_GetPitEntry);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, metisPIT_Closure)
+{
+ MetisPIT *pit = _mockPIT_Create();
+ _MockPIT *mock = metisPIT_Closure(pit);
+ assertTrue(mock == pit->closure, "Wrong pointer expected %p got %p", pit->closure, mock);
+ _metisPIT_Release(&pit);
+}
+
+LONGBOW_TEST_CASE(Global, metisPIT_Release)
+{
+ MetisPIT *pit = _mockPIT_Create();
+ MetisPIT *original = pit;
+ _MockPIT *mock = metisPIT_Closure(pit);
+ metisPIT_Release(&pit);
+
+ assertTrue(mock->countRelease == 1, "Wrong count expected 1 got %u", mock->countRelease);
+ _metisPIT_Release(&original);
+}
+
+LONGBOW_TEST_CASE(Global, metisPIT_ReceiveInterest)
+{
+ MetisPIT *pit = _mockPIT_Create();
+ _MockPIT *mock = metisPIT_Closure(pit);
+ metisPIT_ReceiveInterest(pit, NULL);
+
+ assertTrue(mock->countReceiveInterest == 1, "Wrong count expected 1 got %u", mock->countReceiveInterest);
+ _metisPIT_Release(&pit);
+}
+
+LONGBOW_TEST_CASE(Global, metisPIT_SatisfyInterest)
+{
+ MetisPIT *pit = _mockPIT_Create();
+ _MockPIT *mock = metisPIT_Closure(pit);
+ metisPIT_SatisfyInterest(pit, NULL);
+
+ assertTrue(mock->countSatisfyInterest == 1, "Wrong count expected 1 got %u", mock->countSatisfyInterest);
+ _metisPIT_Release(&pit);
+}
+
+LONGBOW_TEST_CASE(Global, metisPIT_RemoveInterest)
+{
+ MetisPIT *pit = _mockPIT_Create();
+ _MockPIT *mock = metisPIT_Closure(pit);
+ metisPIT_RemoveInterest(pit, NULL);
+
+ assertTrue(mock->countRemoveInterest == 1, "Wrong count expected 1 got %u", mock->countRemoveInterest);
+ _metisPIT_Release(&pit);
+}
+
+LONGBOW_TEST_CASE(Global, metisPIT_GetPitEntry)
+{
+ MetisPIT *pit = _mockPIT_Create();
+ _MockPIT *mock = metisPIT_Closure(pit);
+ metisPIT_GetPitEntry(pit, NULL);
+
+ assertTrue(mock->countGetPitEntry == 1, "Wrong count expected 1 got %u", mock->countGetPitEntry);
+ _metisPIT_Release(&pit);
+}
+
+// ===============================================================================================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metis_PIT);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/metis/ccnx/forwarder/metis/processor/test/test_metis_PitEntry.c b/metis/ccnx/forwarder/metis/processor/test/test_metis_PitEntry.c
new file mode 100644
index 00000000..2ad4b3da
--- /dev/null
+++ b/metis/ccnx/forwarder/metis/processor/test/test_metis_PitEntry.c
@@ -0,0 +1,294 @@
+/*
+ * 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_PitEntry.c"
+#include <LongBow/unit-test.h>
+
+#include <ccnx/forwarder/metis/testdata/metis_TestDataV0.h>
+
+#define __STDC_FORMAT_MACROS
+#include <stdint.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/logging/parc_LogReporterTextStdout.h>
+
+LONGBOW_TEST_RUNNER(metis_PitEntry)
+{
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(metis_PitEntry)
+{
+ 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_PitEntry)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// =====================================================================
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, metisPitEntry_AddEgressId);
+ LONGBOW_RUN_TEST_CASE(Global, metisPitEntry_AddIngressId);
+ LONGBOW_RUN_TEST_CASE(Global, metisPitEntry_Copy);
+ LONGBOW_RUN_TEST_CASE(Global, metisPitEntry_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, metisPitEntry_GetExpiryTime);
+ LONGBOW_RUN_TEST_CASE(Global, metisPitEntry_SetExpiryTime);
+ LONGBOW_RUN_TEST_CASE(Global, metisPitEntry_GetIngressSet);
+ LONGBOW_RUN_TEST_CASE(Global, metisPitEntry_GetEgressSet);
+
+ LONGBOW_RUN_TEST_CASE(Global, metisPitEntry_GetMessage);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, metisPitEntry_AddEgressId)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 2, logger);
+ metisLogger_Release(&logger);
+
+ MetisPitEntry *entry = metisPitEntry_Create(metisMessage_Acquire(interest), 10000, 0);
+
+ metisPitEntry_AddEgressId(entry, 10);
+ metisPitEntry_AddEgressId(entry, 11);
+
+ size_t set_length = metisNumberSet_Length(entry->egressIdSet);
+ bool contains_10 = metisNumberSet_Contains(entry->egressIdSet, 10);
+ bool contains_11 = metisNumberSet_Contains(entry->egressIdSet, 11);
+
+ metisPitEntry_Release(&entry);
+ metisMessage_Release(&interest);
+
+ assertTrue(set_length == 2, "Wrong set length, expected %u got %zu", 2, set_length);
+ assertTrue(contains_10, "Set did not contain 10");
+ assertTrue(contains_11, "Set did not contain 11");
+}
+
+LONGBOW_TEST_CASE(Global, metisPitEntry_AddIngressId)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 2, logger);
+ metisLogger_Release(&logger);
+
+ MetisPitEntry *entry = metisPitEntry_Create(metisMessage_Acquire(interest), 10000, 0);
+
+ metisPitEntry_AddIngressId(entry, 10);
+ metisPitEntry_AddIngressId(entry, 11);
+
+ size_t set_length = metisNumberSet_Length(entry->ingressIdSet);
+
+ // #1 is from the original interest
+ bool contains_1 = metisNumberSet_Contains(entry->ingressIdSet, 1);
+ bool contains_10 = metisNumberSet_Contains(entry->ingressIdSet, 10);
+ bool contains_11 = metisNumberSet_Contains(entry->ingressIdSet, 11);
+
+ metisPitEntry_Release(&entry);
+ metisMessage_Release(&interest);
+
+ assertTrue(set_length == 3, "Wrong set length, expected %u got %zu", 2, set_length);
+ assertTrue(contains_1, "Set did not contain 1");
+ assertTrue(contains_10, "Set did not contain 10");
+ assertTrue(contains_11, "Set did not contain 11");
+}
+
+LONGBOW_TEST_CASE(Global, metisPitEntry_Copy)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 2, logger);
+ metisLogger_Release(&logger);
+
+ MetisPitEntry *entry = metisPitEntry_Create(metisMessage_Acquire(interest), 40000, 0);
+ unsigned refCountBeforeCopy = entry->refcount;
+
+ MetisPitEntry *copy = metisPitEntry_Acquire(entry);
+ unsigned refCountAfterCopy = entry->refcount;
+
+ metisPitEntry_Release(&entry);
+ unsigned refCountAfterDestroy = copy->refcount;
+ metisPitEntry_Release(&copy);
+ metisMessage_Release(&interest);
+
+ assertTrue(refCountAfterCopy == refCountBeforeCopy + 1, "Refcount after copy not 1 larger: expected %u got %u", refCountBeforeCopy + 1, refCountAfterCopy);
+ assertTrue(refCountAfterDestroy == refCountBeforeCopy, "Refcount after destroy not same as before copy: expected %u got %u", refCountBeforeCopy, refCountAfterDestroy);
+}
+
+LONGBOW_TEST_CASE(Global, metisPitEntry_Create_Destroy)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 2, logger);
+ metisLogger_Release(&logger);
+ size_t baselineMemory = parcMemory_Outstanding();
+ MetisPitEntry *entry = metisPitEntry_Create(metisMessage_Acquire(interest), 40000, 0);
+ metisPitEntry_Release(&entry);
+ size_t testMemory = parcMemory_Outstanding();
+
+ metisMessage_Release(&interest);
+
+ assertTrue(testMemory == baselineMemory, "Memory imbalance on create/destroy: expected %zu got %zu", baselineMemory, testMemory);
+}
+
+LONGBOW_TEST_CASE(Global, metisPitEntry_GetExpiryTime)
+{
+ MetisTicks expiry = 40000;
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 2, logger);
+ metisLogger_Release(&logger);
+ MetisPitEntry *entry = metisPitEntry_Create(metisMessage_Acquire(interest), expiry, 0);
+
+ MetisTicks test = metisPitEntry_GetExpiryTime(entry);
+
+ metisPitEntry_Release(&entry);
+ metisMessage_Release(&interest);
+
+ assertTrue(expiry == test, "Got wrong expiry time, expected %" PRIu64 ", got %" PRIu64, expiry, test);
+}
+
+LONGBOW_TEST_CASE(Global, metisPitEntry_SetExpiryTime)
+{
+ MetisTicks expiry = 40000;
+ MetisTicks expiry2 = 80000;
+
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 2, logger);
+ metisLogger_Release(&logger);
+ MetisPitEntry *entry = metisPitEntry_Create(metisMessage_Acquire(interest), expiry, 0);
+
+ metisPitEntry_SetExpiryTime(entry, expiry2);
+
+ MetisTicks test = metisPitEntry_GetExpiryTime(entry);
+
+ metisPitEntry_Release(&entry);
+ metisMessage_Release(&interest);
+
+ assertTrue(expiry2 == test, "Got wrong expiry time, expected %" PRIu64 ", got %" PRIu64, expiry2, test);
+}
+
+LONGBOW_TEST_CASE(Global, metisPitEntry_GetIngressSet)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 2, logger);
+ metisLogger_Release(&logger);
+ MetisPitEntry *entry = metisPitEntry_Create(metisMessage_Acquire(interest), 10000, 0);
+
+ unsigned truth_set[] = { 1, 2, 3, 4, 0 };
+
+ MetisNumberSet *truth = metisNumberSet_Create();
+
+ for (int i = 0; truth_set[i] != 0; i++) {
+ metisNumberSet_Add(truth, truth_set[i]);
+ metisPitEntry_AddIngressId(entry, truth_set[i]);
+ }
+
+ const MetisNumberSet *ingressSet = metisPitEntry_GetIngressSet(entry);
+ bool equals = metisNumberSet_Equals(truth, ingressSet);
+
+ metisPitEntry_Release(&entry);
+ metisMessage_Release(&interest);
+ metisNumberSet_Release(&truth);
+
+ assertTrue(equals, "Number set returned by metisPitEntry_GetIngressSet did not equal truth set");
+}
+
+LONGBOW_TEST_CASE(Global, metisPitEntry_GetEgressSet)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 2, logger);
+ metisLogger_Release(&logger);
+ MetisPitEntry *entry = metisPitEntry_Create(metisMessage_Acquire(interest), 10000, 0);
+
+ unsigned truth_set[] = { 1, 2, 3, 4, 0 };
+
+ MetisNumberSet *truth = metisNumberSet_Create();
+
+ for (int i = 0; truth_set[i] != 0; i++) {
+ metisNumberSet_Add(truth, truth_set[i]);
+ metisPitEntry_AddEgressId(entry, truth_set[i]);
+ }
+
+ const MetisNumberSet *egressSet = metisPitEntry_GetEgressSet(entry);
+ bool equals = metisNumberSet_Equals(truth, egressSet);
+
+ metisPitEntry_Release(&entry);
+ metisMessage_Release(&interest);
+ metisNumberSet_Release(&truth);
+
+ assertTrue(equals, "Number set returned by metisPitEntry_GetIngressSet did not equal truth set");
+}
+
+LONGBOW_TEST_CASE(Global, metisPitEntry_GetMessage)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 2, logger);
+ metisLogger_Release(&logger);
+
+ MetisPitEntry *entry = metisPitEntry_Create(metisMessage_Acquire(interest), 10000, 0);
+ MetisMessage *copy = metisPitEntry_GetMessage(entry);
+
+ assertTrue(copy == interest, "Returned message not equal, expected %p got %p", (void *) interest, (void *) entry);
+
+ metisPitEntry_Release(&entry);
+ metisMessage_Release(&copy);
+ metisMessage_Release(&interest);
+}
+
+// =====================================================================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metis_PitEntry);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/metis/ccnx/forwarder/metis/processor/test/test_metis_StandardPIT.c b/metis/ccnx/forwarder/metis/processor/test/test_metis_StandardPIT.c
new file mode 100644
index 00000000..b04a3964
--- /dev/null
+++ b/metis/ccnx/forwarder/metis/processor/test/test_metis_StandardPIT.c
@@ -0,0 +1,498 @@
+/*
+ * 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 tests were written before MetisMatchRulesTable was broken out of the PIT.
+ * So, many of the tests "cheat" by looking directly in a constiuent table in MetisMatchingRulesTable.
+ * They should be re-written to use the MetisMatchingRulesTable API.
+ */
+
+// Include this so we can step the clock forward without waiting real time
+#include "../../core/metis_Forwarder.c"
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../metis_StandardPIT.c"
+
+// so we can directly test the underlying tables
+#include "../metis_MatchingRulesTable.c"
+
+// test data set
+#include <ccnx/forwarder/metis/testdata/metis_TestDataV0.h>
+
+#include <LongBow/unit-test.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/logging/parc_LogReporterTextStdout.h>
+
+#include <parc/logging/parc_LogReporterTextStdout.h>
+
+MetisForwarder *metis;
+
+LONGBOW_TEST_RUNNER(metis_PIT)
+{
+ // 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_PIT)
+{
+ 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_PIT)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ===============================================================================================
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, metisPit_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, metisPit_ReceiveInterest_NewEntry);
+ LONGBOW_RUN_TEST_CASE(Global, metisPit_ReceiveInterest_ExistingExpired);
+ LONGBOW_RUN_TEST_CASE(Global, metisPit_ReceiveInterest_ExistingExpired_VerifyTable);
+ LONGBOW_RUN_TEST_CASE(Global, metisPit_ReceiveInterest_ExistingCurrentSameReversePath);
+ LONGBOW_RUN_TEST_CASE(Global, metisPit_ReceiveInterest_ExistingCurrentNewReversePath);
+ LONGBOW_RUN_TEST_CASE(Global, metisPit_SatisfyInterest);
+ LONGBOW_RUN_TEST_CASE(Global, metisPIT_RemoveInterest);
+ LONGBOW_RUN_TEST_CASE(Global, metisPIT_AddEgressConnectionId);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ metis = metisForwarder_Create(NULL);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ metisForwarder_Destroy(&metis);
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, metisPit_Create_Destroy)
+{
+ metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ size_t baselineMemory = parcMemory_Outstanding();
+
+ MetisPIT *pit = metisStandardPIT_Create(metis);
+ metisPIT_Release(&pit);
+
+ assertTrue(parcMemory_Outstanding() == baselineMemory, "Memory imbalance on create/destroy: %u", parcMemory_Outstanding());
+}
+
+/**
+ * Receive an interest that is not already in the table
+ */
+LONGBOW_TEST_CASE(Global, metisPit_ReceiveInterest_NewEntry)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisPIT *generic = metisStandardPIT_Create(metis);
+ MetisStandardPIT *pit = metisPIT_Closure(generic);
+
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ parcLogReporter_Release(&reporter);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 1, logger);
+ metisLogger_Release(&logger);
+
+ MetisPITVerdict verdict = metisPIT_ReceiveInterest(generic, interest);
+ size_t table_length = parcHashCodeTable_Length(pit->table->tableByName);
+
+ metisMessage_Release(&interest);
+
+ metisPIT_Release(&generic);
+ metisForwarder_Destroy(&metis);
+
+ assertTrue(table_length == 1, "tableByName wrong length, expected %u got %zu", 1, table_length);
+ assertTrue(verdict == MetisPITVerdict_Forward, "New entry did not return PIT_VERDICT_NEW_ENTRY, got %d", verdict);
+}
+
+/**
+ * Receive an interest that is in the table, but expired
+ */
+LONGBOW_TEST_CASE(Global, metisPit_ReceiveInterest_ExistingExpired)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisPIT *generic = metisStandardPIT_Create(metis);
+ MetisStandardPIT *pit = metisPIT_Closure(generic);
+
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ MetisMessage *interest_1 = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 1, logger);
+ MetisMessage *interest_2 = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 2, 2, logger);
+
+ // stuff in the first interest
+ _metisPIT_StoreInTable(pit, interest_1);
+
+ // we need to crank the clock forward over 4 seconds, so add 5 seconds to the clock
+ metis->clockOffset = metisForwarder_NanosToTicks(5000000000ULL);
+
+ // now do the operation we're testing. The previous entry should show as expired
+ MetisPITVerdict verdict_2 = metisPIT_ReceiveInterest(generic, interest_2);
+
+ size_t table_length = parcHashCodeTable_Length(pit->table->tableByName);
+
+ metisMessage_Release(&interest_1);
+ metisMessage_Release(&interest_2);
+
+ metisPIT_Release(&generic);
+ metisForwarder_Destroy(&metis);
+
+ assertTrue(table_length == 1, "tableByName wrong length, expected %u got %zu", 1, table_length);
+ assertTrue(verdict_2 == MetisPITVerdict_Forward, "New entry did not return PIT_VERDICT_NEW_ENTRY, got %d", verdict_2);
+}
+
+/**
+ * Receive an interest that is in the table, but expired.
+ * In this test, retrieve the interest from the table and make sure its the 2nd one.
+ */
+LONGBOW_TEST_CASE(Global, metisPit_ReceiveInterest_ExistingExpired_VerifyTable)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisPIT *generic = metisStandardPIT_Create(metis);
+ MetisStandardPIT *pit = metisPIT_Closure(generic);
+
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ MetisMessage *interest_1 = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 1, logger);
+ MetisMessage *interest_2 = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 2, 2, logger);
+
+ // stuff in the first interest
+ _metisPIT_StoreInTable(pit, interest_1);
+
+ // we need to crank the clock forward over 4 seconds, so add 5 seconds to the clock
+ metis->clockOffset = metisForwarder_NanosToTicks(5000000000ULL);
+
+ // now do the operation we're testing. The previous entry should show as expired
+ metisPIT_ReceiveInterest(generic, interest_2);
+
+ MetisPitEntry *entry = parcHashCodeTable_Get(pit->table->tableByName, interest_2);
+ const MetisNumberSet *ingressSet = metisPitEntry_GetIngressSet(entry);
+ bool containsTwo = metisNumberSet_Contains(ingressSet, 2);
+
+ metisMessage_Release(&interest_1);
+ metisMessage_Release(&interest_2);
+ metisPIT_Release(&generic);
+ metisForwarder_Destroy(&metis);
+
+ assertTrue(containsTwo, "Got wrong ingressId, does not contain %u", 2);
+}
+
+/**
+ * Receive an interest that is in the table, and not expired, and from an existing reverse path.
+ * This should cause the interest to be forwarded.
+ */
+LONGBOW_TEST_CASE(Global, metisPit_ReceiveInterest_ExistingCurrentSameReversePath)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisPIT *generic = metisStandardPIT_Create(metis);
+ MetisStandardPIT *pit = metisPIT_Closure(generic);
+
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ MetisMessage *interest_1 = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 1, logger);
+ MetisMessage *interest_2 = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 2, logger);
+
+ // stuff in the first interest
+ _metisPIT_StoreInTable(pit, interest_1);
+
+ // now do the operation we're testing
+ MetisPITVerdict verdict_2 = metisPIT_ReceiveInterest(generic, interest_2);
+ size_t table_length = parcHashCodeTable_Length(pit->table->tableByName);
+
+ metisMessage_Release(&interest_1);
+ metisMessage_Release(&interest_2);
+ metisPIT_Release(&generic);
+ metisForwarder_Destroy(&metis);
+
+ assertTrue(table_length == 1, "tableByName wrong length, expected %u got %zu", 1, table_length);
+ assertTrue(verdict_2 == MetisPITVerdict_Forward, "New entry did not return MetisPITVerdict_Forward, got %d", verdict_2);
+}
+
+/*
+ * Receive an interest that exists in the PIT but from a new reverse path. this should be
+ * aggregated as an existing entry.
+ */
+LONGBOW_TEST_CASE(Global, metisPit_ReceiveInterest_ExistingCurrentNewReversePath)
+{
+ printf("THE TEST\n");
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisPIT *generic = metisStandardPIT_Create(metis);
+ MetisStandardPIT *pit = metisPIT_Closure(generic);
+
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ MetisMessage *interest_1 = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 1, logger);
+ MetisMessage *interest_2 = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 2, 2, logger);
+
+ // stuff in the first interest
+ _metisPIT_StoreInTable(pit, interest_1);
+
+ // now do the operation we're testing
+ MetisPITVerdict verdict_2 = metisPIT_ReceiveInterest(generic, interest_2);
+ size_t table_length = parcHashCodeTable_Length(pit->table->tableByName);
+
+ metisMessage_Release(&interest_1);
+ metisMessage_Release(&interest_2);
+ metisPIT_Release(&generic);
+ metisForwarder_Destroy(&metis);
+
+ assertTrue(table_length == 1, "tableByName wrong length, expected %u got %zu", 1, table_length);
+ assertTrue(verdict_2 == MetisPITVerdict_Aggregate, "New entry did not return MetisPITVerdict_Aggregate, got %d", verdict_2);
+}
+
+
+LONGBOW_TEST_CASE(Global, metisPit_SatisfyInterest)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisPIT *generic = metisStandardPIT_Create(metis);
+ MetisStandardPIT *pit = metisPIT_Closure(generic);
+
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName_objecthash, sizeof(metisTestDataV0_InterestWithName_objecthash), 1, 1, logger);
+ MetisMessage *contentObjectMessage = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject), 1, 1, logger);
+
+ // we manually stuff it in to the proper table, then call the public API, which will
+ // figure out the right table then remove it.
+ size_t before = parcHashCodeTable_Length(pit->table->tableByName);
+ _metisPIT_StoreInTable(pit, interest);
+ MetisNumberSet *ingressSetUnion = metisPIT_SatisfyInterest(generic, contentObjectMessage);
+ metisPIT_RemoveInterest(generic, interest);
+ assertTrue(metisNumberSet_Length(ingressSetUnion) == 1, "Unexpected satisfy interest return set size (%zu)",
+ metisNumberSet_Length(ingressSetUnion));
+ size_t after = parcHashCodeTable_Length(pit->table->tableByName);
+
+ metisNumberSet_Release(&ingressSetUnion);
+ metisMessage_Release(&interest);
+ metisMessage_Release(&contentObjectMessage);
+ metisPIT_Release(&generic);
+ metisForwarder_Destroy(&metis);
+
+ assertTrue(after == before, "Did not remove interest in HashCodeTable: before %zu after %zu", before, after);
+}
+
+LONGBOW_TEST_CASE(Global, metisPIT_RemoveInterest)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisPIT *generic = metisStandardPIT_Create(metis);
+ MetisStandardPIT *pit = metisPIT_Closure(generic);
+
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 1, logger);
+
+ // we manually stuff it in to the proper table, then call the public API, which will
+ // figure out the right table then remove it.
+ size_t before = parcHashCodeTable_Length(pit->table->tableByName);
+ _metisPIT_StoreInTable(pit, interest);
+ metisPIT_RemoveInterest(generic, interest);
+ size_t after = parcHashCodeTable_Length(pit->table->tableByName);
+
+ metisMessage_Release(&interest);
+ metisPIT_Release(&generic);
+ metisForwarder_Destroy(&metis);
+
+ assertTrue(after == before, "Did not remove interest in HashCodeTable: before %zu after %zu", before, after);
+}
+
+LONGBOW_TEST_CASE(Global, metisPIT_AddEgressConnectionId)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisPIT *generic = metisStandardPIT_Create(metis);
+ MetisStandardPIT *pit = metisPIT_Closure(generic);
+
+ MetisLogger *logger = metisForwarder_GetLogger(metis);
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 1, logger);
+
+ _metisPIT_StoreInTable(pit, interest);
+ _metisPIT_AddEgressConnectionId(generic, interest, 6);
+
+ MetisPitEntry *entry = metisPIT_GetPitEntry(generic, interest);
+ const MetisNumberSet *egressSet = metisPitEntry_GetEgressSet(entry);
+
+ size_t egress_length = metisNumberSet_Length(egressSet);
+ bool contains_6 = metisNumberSet_Contains(egressSet, 6);
+
+ metisPitEntry_Release(&entry);
+ metisMessage_Release(&interest);
+ metisPIT_Release(&generic);
+ metisForwarder_Destroy(&metis);
+
+ assertTrue(egress_length == 1, "Wrong egress_set length, expected %u got %zu", 1, egress_length);
+ assertTrue(contains_6, "Wrong egress_set match, did not contain %u", 6);
+}
+
+// ===============================================================================================
+
+LONGBOW_TEST_FIXTURE(Local)
+{
+ LONGBOW_RUN_TEST_CASE(Local, metisPit_PitEntryDestroyer);
+ LONGBOW_RUN_TEST_CASE(Local, _metisPIT_StoreInTable);
+ LONGBOW_RUN_TEST_CASE(Local, metisPit_StoreInTable_IngressSetCheck);
+ LONGBOW_RUN_TEST_CASE(Local, _metisPIT_CalculateLifetime_WithLifetime);
+ LONGBOW_RUN_TEST_CASE(Local, _metisPIT_CalculateLifetime_DefaultLifetime);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Local)
+{
+ metis = metisForwarder_Create(NULL);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Local)
+{
+ metisForwarder_Destroy(&metis);
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Local, metisPit_PitEntryDestroyer)
+{
+ testUnimplemented("This test is unimplemented");
+}
+
+LONGBOW_TEST_CASE(Local, _metisPIT_StoreInTable)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisPIT *generic = metisStandardPIT_Create(metis);
+ MetisStandardPIT *pit = metisPIT_Closure(generic);
+
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ parcLogReporter_Release(&reporter);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 1, logger);
+ metisLogger_Release(&logger);
+
+ size_t before = parcHashCodeTable_Length(pit->table->tableByName);
+ _metisPIT_StoreInTable(pit, interest);
+ size_t after = parcHashCodeTable_Length(pit->table->tableByName);
+
+ metisMessage_Release(&interest);
+ metisPIT_Release(&generic);
+ metisForwarder_Destroy(&metis);
+
+ assertTrue(after == before + 1, "Did not store interest in HashCodeTable: before %zu after %zu", before, after);
+}
+
+LONGBOW_TEST_CASE(Local, metisPit_StoreInTable_IngressSetCheck)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisPIT *generic = metisStandardPIT_Create(metis);
+ MetisStandardPIT *pit = metisPIT_Closure(generic);
+
+ unsigned connid = 99;
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ parcLogReporter_Release(&reporter);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), connid, 1, logger);
+ metisLogger_Release(&logger);
+
+ _metisPIT_StoreInTable(pit, interest);
+ MetisPitEntry *entry = parcHashCodeTable_Get(pit->table->tableByName, interest);
+ const MetisNumberSet *ingressSet = metisPitEntry_GetIngressSet(entry);
+ bool containsIngressId = metisNumberSet_Contains(ingressSet, connid);
+
+ metisMessage_Release(&interest);
+ metisPIT_Release(&generic);
+ metisForwarder_Destroy(&metis);
+
+ assertTrue(containsIngressId, "PIT entry did not have the ingress id in its ingress set");
+}
+
+/*
+ * Use an interest with a lifetime
+ */
+LONGBOW_TEST_CASE(Local, _metisPIT_CalculateLifetime_WithLifetime)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisPIT *generic = metisStandardPIT_Create(metis);
+ MetisStandardPIT *pit = metisPIT_Closure(generic);
+
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ parcLogReporter_Release(&reporter);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_SecondInterest, sizeof(metisTestDataV0_SecondInterest), 1, 1, logger);
+ metisLogger_Release(&logger);
+
+ MetisTicks now = metisForwarder_GetTicks(metis);
+ MetisTicks lifetime = _metisPIT_CalculateLifetime(pit, interest);
+
+ metisMessage_Release(&interest);
+ metisPIT_Release(&generic);
+ metisForwarder_Destroy(&metis);
+
+ uint64_t value = 32000;
+ assertTrue(lifetime >= value + now, "Wrong lifetime, should be at least %" PRIu64 ", got %" PRIu64, now + value, lifetime);
+}
+
+/*
+ * Use an interest without a Lifetime, should return with the default 4s lifetime
+ */
+LONGBOW_TEST_CASE(Local, _metisPIT_CalculateLifetime_DefaultLifetime)
+{
+ MetisForwarder *metis = metisForwarder_Create(NULL);
+ MetisPIT *generic = metisStandardPIT_Create(metis);
+ MetisStandardPIT *pit = metisPIT_Closure(generic);
+
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ parcLogReporter_Release(&reporter);
+ MetisMessage *interest = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName, sizeof(metisTestDataV0_InterestWithName), 1, 1, logger);
+ metisLogger_Release(&logger);
+
+ MetisTicks now = metisForwarder_GetTicks(metis);
+ MetisTicks lifetime = _metisPIT_CalculateLifetime(pit, interest);
+
+ metisMessage_Release(&interest);
+ metisPIT_Release(&generic);
+ metisForwarder_Destroy(&metis);
+
+ assertTrue(lifetime >= 4000 + now, "Wrong lifetime, should be at least %" PRIu64 ", got %" PRIu64, now + 4000, lifetime);
+}
+
+
+
+// ===============================================================================================
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metis_PIT);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/metis/ccnx/forwarder/metis/processor/test/testrig_MockTap.h b/metis/ccnx/forwarder/metis/processor/test/testrig_MockTap.h
new file mode 100644
index 00000000..e6c7e967
--- /dev/null
+++ b/metis/ccnx/forwarder/metis/processor/test/testrig_MockTap.h
@@ -0,0 +1,104 @@
+/*
+ * 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_MockTap_h
+#define Metis_testrig_MockTap_h
+
+// =========================================================================
+// Mock for tap testing
+// Allows the test to set the IsTapOnX return values.
+// Counts the number of calls to each TapOnX.
+// Records the last message pointer
+// The user sets and examines values in the static "testTap" variable and
+// passes "testTapTemplate" to the tap setup.
+
+static bool testTap_IsTapOnReceive(const MetisTap *tap);
+static bool testTap_IsTapOnSend(const MetisTap *tap);
+static bool testTap_IsTapOnDrop(const MetisTap *tap);
+static void testTap_TapOnReceive(MetisTap *tap, const MetisMessage *message);
+static void testTap_TapOnSend(MetisTap *tap, const MetisMessage *message);
+static void testTap_TapOnDrop(MetisTap *tap, const MetisMessage *message);
+
+// this test variable is zeroed in each FIXTURE_SETUP.
+// To test tap functionality, set the various callOnX flags, run your test,
+// then check the onXCounts to make sure they are right.
+struct testTap_s {
+ bool callOnReceive;
+ bool callOnSend;
+ bool callOnDrop;
+ unsigned onReceiveCount;
+ unsigned onSendCount;
+ unsigned onDropCount;
+
+ const MetisMessage *lastMessage;
+} testTap;
+
+// you should not need tochange this template
+MetisTap testTapTemplate = {
+ .context = &testTap,
+ .isTapOnReceive = &testTap_IsTapOnReceive,
+ .isTapOnSend = &testTap_IsTapOnSend,
+ .isTapOnDrop = &testTap_IsTapOnDrop,
+ .tapOnReceive = &testTap_TapOnReceive,
+ .tapOnSend = &testTap_TapOnSend,
+ .tapOnDrop = &testTap_TapOnDrop
+};
+
+static bool
+testTap_IsTapOnReceive(const MetisTap *tap)
+{
+ struct testTap_s *mytap = (struct testTap_s *) tap->context;
+ return mytap->callOnReceive;
+}
+
+static bool
+testTap_IsTapOnSend(const MetisTap *tap)
+{
+ struct testTap_s *mytap = (struct testTap_s *) tap->context;
+ return mytap->callOnSend;
+}
+
+static bool
+testTap_IsTapOnDrop(const MetisTap *tap)
+{
+ struct testTap_s *mytap = (struct testTap_s *) tap->context;
+ return mytap->callOnDrop;
+}
+
+static void
+testTap_TapOnReceive(MetisTap *tap, const MetisMessage *message)
+{
+ struct testTap_s *mytap = (struct testTap_s *) tap->context;
+ mytap->onReceiveCount++;
+ mytap->lastMessage = message;
+}
+
+static void
+testTap_TapOnSend(MetisTap *tap, const MetisMessage *message)
+{
+ struct testTap_s *mytap = (struct testTap_s *) tap->context;
+ mytap->onSendCount++;
+ mytap->lastMessage = message;
+}
+
+static void
+testTap_TapOnDrop(MetisTap *tap, const MetisMessage *message)
+{
+ struct testTap_s *mytap = (struct testTap_s *) tap->context;
+ mytap->onDropCount++;
+ mytap->lastMessage = message;
+}
+#endif // Metis_testrig_MockTap_h