aboutsummaryrefslogtreecommitdiffstats
path: root/metis/ccnx/forwarder/metis/content_store/test/test_metis_LRUContentStore.c
diff options
context:
space:
mode:
Diffstat (limited to 'metis/ccnx/forwarder/metis/content_store/test/test_metis_LRUContentStore.c')
-rw-r--r--metis/ccnx/forwarder/metis/content_store/test/test_metis_LRUContentStore.c788
1 files changed, 788 insertions, 0 deletions
diff --git a/metis/ccnx/forwarder/metis/content_store/test/test_metis_LRUContentStore.c b/metis/ccnx/forwarder/metis/content_store/test/test_metis_LRUContentStore.c
new file mode 100644
index 00000000..ea55b361
--- /dev/null
+++ b/metis/ccnx/forwarder/metis/content_store/test/test_metis_LRUContentStore.c
@@ -0,0 +1,788 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+
+#include "../metis_LRUContentStore.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_LRUContentStore)
+{
+ 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_LRUContentStore)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(metis_LRUContentStore)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// ============================================================================
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, metisLRUContentStore_Create_Destroy);
+ LONGBOW_RUN_TEST_CASE(Global, metisLRUContentStore_Log);
+
+ LONGBOW_RUN_TEST_CASE(Global, metisLRUContentStore_Create_ZeroCapacity);
+ LONGBOW_RUN_TEST_CASE(Global, metisLRUContentStore_Fetch_ByName);
+ LONGBOW_RUN_TEST_CASE(Global, metisLRUContentStore_Fetch_ByNameAndKeyId);
+ LONGBOW_RUN_TEST_CASE(Global, metisLRUContentStore_Fetch_ByNameAndObjectHash);
+
+ LONGBOW_RUN_TEST_CASE(Global, metisLRUContentStore_Remove_Content);
+ LONGBOW_RUN_TEST_CASE(Global, metisLRUContentStore_Remove_NonExistentContent);
+
+ LONGBOW_RUN_TEST_CASE(Global, metisLRUContentStore_Fetch_Lru);
+
+ LONGBOW_RUN_TEST_CASE(Global, metisLRUContentStore_Save_ZeroCapacity);
+ LONGBOW_RUN_TEST_CASE(Global, metisLRUContentStore_Save_CapacityLimit);
+ LONGBOW_RUN_TEST_CASE(Global, metisLRUContentStore_Save_WithoutEviction);
+ LONGBOW_RUN_TEST_CASE(Global, metisLRUContentStore_Save_WithEviction);
+
+ LONGBOW_RUN_TEST_CASE(Global, metisLRUContentStore_Save_WithEvictionByExpiryTime);
+ LONGBOW_RUN_TEST_CASE(Global, metisLRUContentStore_Save_WithEvictionByRCT);
+
+ LONGBOW_RUN_TEST_CASE(Global, metisLRUContentStore_Save_ExpiredContent);
+
+ LONGBOW_RUN_TEST_CASE(Global, metisLRUContentStore_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;
+}
+
+static MetisContentStoreInterface *
+_createLRUContentStore(size_t capacity)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+
+ MetisContentStoreConfig config = {
+ .objectCapacity = capacity,
+ };
+
+ MetisContentStoreInterface *store = metisLRUContentStore_Create(&config, logger);
+
+ metisLogger_Release(&logger);
+
+ return store;
+}
+
+static MetisMessage *
+_createUniqueMetisMessage(MetisLogger *logger, int tweakNumber, uint8_t *template, size_t templateSize, int nameOffset)
+{
+ 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);
+ parcBuffer_Release(&buffer);
+
+ return result;
+}
+
+LONGBOW_TEST_CASE(Global, metisLRUContentStore_Create_Destroy)
+{
+ MetisContentStoreInterface *store = _createLRUContentStore(10);
+ assertNotNull(store, "Expected to init a content store");
+ metisContentStoreInterface_Release(&store);
+}
+
+LONGBOW_TEST_CASE(Global, metisLRUContentStore_Log)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+
+ size_t capacity = 20;
+ MetisContentStoreInterface *store = _createLRUContentStore(capacity);
+
+ for (int i = 1; i <= capacity; i++) {
+ int offsetOfNameInEncodedObject = metisTestDataV0_EncodedObject_name.offset + 4;
+
+ MetisMessage *object = _createUniqueMetisMessage(logger, i,
+ metisTestDataV0_EncodedObject,
+ sizeof(metisTestDataV0_EncodedObject),
+ offsetOfNameInEncodedObject);
+
+ bool success = metisContentStoreInterface_PutContent(store, object, 1);
+ metisMessage_Release(&object);
+
+ assertTrue(success, "Unexpectedly failed to add entry to ContentStore");
+ }
+
+ metisContentStoreInterface_Log(store);
+
+ metisLogger_Release(&logger);
+ metisContentStoreInterface_Release(&store);
+}
+
+LONGBOW_TEST_CASE(Global, metisLRUContentStore_Create_ZeroCapacity)
+{
+ size_t capacity = 10;
+ MetisContentStoreInterface *store = _createLRUContentStore(capacity);
+
+ assertTrue(metisContentStoreInterface_GetObjectCapacity(store) == capacity, "Wrong capacity, expected %zu got %zu",
+ capacity, metisContentStoreInterface_GetObjectCapacity(store));
+
+ assertTrue(metisContentStoreInterface_GetObjectCount(store) == 0, "Wrong initial count, expected %u got %zu", 0,
+ metisContentStoreInterface_GetObjectCount(store));
+ metisContentStoreInterface_Release(&store);
+}
+
+LONGBOW_TEST_CASE(Global, metisLRUContentStore_Fetch_ByName)
+{
+ size_t capacity = 10;
+ MetisContentStoreInterface *store = _createLRUContentStore(capacity);
+
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+
+ uint64_t expiryTime = 300l;
+ uint64_t rct = 200;
+ uint64_t now = 100;
+
+ MetisMessage *object_1 = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject,
+ sizeof(metisTestDataV0_EncodedObject), 1, 2, logger);
+
+ metisMessage_SetExpiryTimeTicks(object_1, expiryTime);
+ metisMessage_SetRecommendedCacheTimeTicks(object_1, rct);
+
+ MetisMessage *object_2 = metisMessage_CreateFromArray(metisTestDataV0_SecondObject,
+ sizeof(metisTestDataV0_SecondObject), 1, 2, logger);
+ metisMessage_SetExpiryTimeTicks(object_2, expiryTime);
+ metisMessage_SetRecommendedCacheTimeTicks(object_2, rct);
+
+ metisMessage_SetExpiryTimeTicks(object_1, expiryTime);
+ metisMessage_SetRecommendedCacheTimeTicks(object_1, rct);
+
+ metisContentStoreInterface_PutContent(store, object_1, now);
+ metisContentStoreInterface_PutContent(store, object_2, now);
+
+ MetisMessage *interestByName = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName,
+ sizeof(metisTestDataV0_InterestWithName), 3, 5, logger);
+
+
+ MetisMessage *testObject = metisContentStoreInterface_MatchInterest(store, interestByName);
+ assertNotNull(testObject, "Fetch did not find match when it should have");
+
+ uint64_t expiryTimeOut = metisMessage_GetExpiryTimeTicks(testObject);
+ uint64_t rctOut = metisMessage_GetRecommendedCacheTimeTicks(testObject);
+ bool hasExpiryTime = metisMessage_HasExpiryTime(testObject);
+ bool hasRCT = metisMessage_HasRecommendedCacheTime(testObject);
+
+ assertTrue(hasRCT, "Expected object to have an RCT");
+ assertTrue(hasExpiryTime, "Expected object to have an ExpiryTime");
+ assertTrue(expiryTime == expiryTimeOut, "Expected the same expiryTime to be retrieved");
+ assertTrue(rct == rctOut, "Expected the same RCT to be retrieved");
+
+ // 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);
+
+ metisContentStoreInterface_Release(&store);
+ metisLogger_Release(&logger);
+ metisMessage_Release(&object_1);
+ metisMessage_Release(&object_2);
+ metisMessage_Release(&interestByName);
+}
+
+
+LONGBOW_TEST_CASE(Global, metisLRUContentStore_Fetch_ByNameAndKeyId)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+
+ size_t capacity = 10;
+ MetisContentStoreInterface *store = _createLRUContentStore(capacity);
+
+ 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);
+
+ metisContentStoreInterface_PutContent(store, object_1, 1);
+ metisContentStoreInterface_PutContent(store, object_2, 1);
+
+ MetisMessage *interestByNameKeyId = metisMessage_CreateFromArray(metisTestDataV0_InterestWithName_keyid,
+ sizeof(metisTestDataV0_InterestWithName_keyid),
+ 3, 5, logger);
+
+ MetisMessage *testObject = metisContentStoreInterface_MatchInterest(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);
+
+ metisContentStoreInterface_Release(&store);
+ metisLogger_Release(&logger);
+ metisMessage_Release(&object_1);
+ metisMessage_Release(&object_2);
+ metisMessage_Release(&interestByNameKeyId);
+}
+
+LONGBOW_TEST_CASE(Global, metisLRUContentStore_Fetch_ByNameAndObjectHash)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+
+ size_t capacity = 10;
+ MetisContentStoreInterface *store = _createLRUContentStore(capacity);
+
+ 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);
+
+ uint64_t expiryTime = 300l;
+ uint64_t rct = 200l;
+ uint64_t now = 100l;
+
+ metisMessage_SetExpiryTimeTicks(object_1, expiryTime);
+ metisMessage_SetRecommendedCacheTimeTicks(object_1, rct);
+
+ metisContentStoreInterface_PutContent(store, object_1, now);
+ metisContentStoreInterface_PutContent(store, object_2, now);
+
+ 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 = metisContentStoreInterface_MatchInterest(store, interestByNameObjectHash);
+
+ assertTrue(expiryTime == metisMessage_GetExpiryTimeTicks(testObject), "Expected the same expiryTime to be retrieved");
+ assertTrue(rct == metisMessage_GetRecommendedCacheTimeTicks(testObject), "Expected the same RCT to be retrieved");
+
+ 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);
+
+ metisContentStoreInterface_Release(&store);
+ metisLogger_Release(&logger);
+ metisMessage_Release(&object_1);
+ metisMessage_Release(&object_2);
+ metisMessage_Release(&interestByNameObjectHash);
+}
+
+LONGBOW_TEST_CASE(Global, metisLRUContentStore_Remove_Content)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+
+ size_t capacity = 10;
+ MetisContentStoreInterface *store = _createLRUContentStore(capacity);
+
+ 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);
+
+ metisMessage_SetExpiryTimeTicks(object_1, 200);
+ metisMessage_SetRecommendedCacheTimeTicks(object_1, 100);
+
+ metisContentStoreInterface_PutContent(store, object_1, 10);
+ metisContentStoreInterface_PutContent(store, object_2, 10);
+
+ assertTrue(metisContentStoreInterface_GetObjectCount(store) == 2, "Expected 2 objects in the metisContentStoreInterface_");
+
+ 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 = metisContentStoreInterface_MatchInterest(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);
+
+ // Now remove it.
+ metisContentStoreInterface_RemoveContent(store, object_1); // Releases the contained Message
+
+ assertTrue(metisContentStoreInterface_GetObjectCount(store) == 1, "Expected 1 object in the store, got %zu",
+ metisContentStoreInterface_GetObjectCount(store));
+
+ MetisMessage *nullObject = metisContentStoreInterface_MatchInterest(store, interestByNameObjectHash);
+
+ assertNull(nullObject, "Fetch found a match when it should not have");
+
+ metisContentStoreInterface_Release(&store);
+ metisLogger_Release(&logger);
+ metisMessage_Release(&object_1);
+ metisMessage_Release(&object_2);
+ metisMessage_Release(&interestByNameObjectHash);
+}
+
+LONGBOW_TEST_CASE(Global, metisLRUContentStore_Remove_NonExistentContent)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+
+ size_t capacity = 10;
+ MetisContentStoreInterface *store = _createLRUContentStore(capacity);
+
+ 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);
+
+ metisContentStoreInterface_PutContent(store, object_1, 1);
+
+ assertTrue(metisContentStoreInterface_GetObjectCount(store) == 1, "Expected 1 object in the metisContentStoreInterface_");
+
+ // Try to remove one that is not in the store.
+ bool result = metisContentStoreInterface_RemoveContent(store, object_2); // Releases the contained Message
+ assertFalse(result, "Expected to NOT remove object_2");
+
+ assertTrue(metisContentStoreInterface_GetObjectCount(store) == 1, "Expected 1 object in the metisContentStoreInterface_");
+
+ result = metisContentStoreInterface_RemoveContent(store, object_1); // Releases the contained Message
+ assertTrue(result, "Expected to remove object_1");
+
+ assertTrue(metisContentStoreInterface_GetObjectCount(store) == 0, "Expected 0 objects in the metisContentStoreInterface_");
+
+ metisContentStoreInterface_Release(&store);
+ metisLogger_Release(&logger);
+ metisMessage_Release(&object_1);
+ metisMessage_Release(&object_2);
+}
+
+/*
+ * Create an cache and access objects to make sure the LRU is evicting the right way
+ */
+LONGBOW_TEST_CASE(Global, metisLRUContentStore_Fetch_Lru)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ metisLogger_SetLogLevel(logger, MetisLoggerFacility_Processor, PARCLogLevel_Debug);
+ parcLogReporter_Release(&reporter);
+
+ size_t capacity = 2;
+ MetisContentStoreInterface *store = _createLRUContentStore(capacity);
+
+ 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);
+
+ metisContentStoreInterface_PutContent(store, object1, 1);
+ metisContentStoreInterface_PutContent(store, object2, 1);
+
+ // 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 = metisContentStoreInterface_MatchInterest(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);
+ metisContentStoreInterface_PutContent(store, object3, 1);
+
+ // object 2 should be evicted
+ MetisMessage *interestOtherName = metisMessage_CreateFromArray(metisTestDataV0_InterestWithOtherName,
+ sizeof(metisTestDataV0_InterestWithOtherName), 5, 5, logger);
+ MetisMessage *testEvictedObject = metisContentStoreInterface_MatchInterest(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 = metisContentStoreInterface_MatchInterest(store, interestByName);
+
+ assertNotNull(testObject1Again, "Did not retrieve object1 from the content store");
+
+ metisContentStoreInterface_Release(&store);
+ metisLogger_Release(&logger);
+ metisMessage_Release(&object1);
+ metisMessage_Release(&object2);
+ metisMessage_Release(&object3);
+ metisMessage_Release(&interestByName);
+ metisMessage_Release(&interestOtherName);
+}
+
+
+LONGBOW_TEST_CASE(Global, metisLRUContentStore_Save_WithoutEviction)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+
+ size_t capacity = 10;
+ MetisContentStoreInterface *store = _createLRUContentStore(capacity);
+
+ 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);
+
+ metisContentStoreInterface_PutContent(store, object_1, 10);
+ metisContentStoreInterface_PutContent(store, object_2, 10);
+
+ _MetisLRUContentStore *internalStore = ( _MetisLRUContentStore *) metisContentStoreInterface_GetPrivateData(store);
+ _MetisLRUContentStoreStats *stats = &internalStore->stats;
+
+ assertTrue(stats->countAdds == 2, "Wrong countAdds, expected %u got %" PRIu64, 2, stats->countAdds);
+ assertTrue(stats->countLruEvictions == 0, "Wrong countLruEvictions, expected %u got %" PRIu64, 0, stats->countLruEvictions);
+ assertTrue(metisLruList_Length(internalStore->lru) == 2, "Wrong metisLruList_Length, expected %u got %zu", 2,
+ metisLruList_Length(internalStore->lru));
+
+ metisContentStoreInterface_Release(&store);
+ metisLogger_Release(&logger);
+ metisMessage_Release(&object_1);
+ metisMessage_Release(&object_2);
+}
+
+LONGBOW_TEST_CASE(Global, metisLRUContentStore_Save_WithEviction)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+
+ size_t capacity = 1;
+ MetisContentStoreInterface *store = _createLRUContentStore(capacity);
+
+ MetisMessage *content_1 = _createUniqueMetisMessage(logger, 1, metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject),
+ metisTestDataV0_EncodedObject_name.offset + 4);
+
+ MetisMessage *content_2 = _createUniqueMetisMessage(logger, 2, metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject),
+ metisTestDataV0_EncodedObject_name.offset + 4);
+
+ MetisMessage *content_3 = _createUniqueMetisMessage(logger, 3, metisTestDataV0_EncodedObject, sizeof(metisTestDataV0_EncodedObject),
+ metisTestDataV0_EncodedObject_name.offset + 4);
+
+
+ metisContentStoreInterface_PutContent(store, content_1, 1);
+
+ assertTrue(metisContentStoreInterface_GetObjectCount(store) == 1, "Wrong objectCount. Expected %u, got %zu", 1, metisContentStoreInterface_GetObjectCount(store));
+
+ metisContentStoreInterface_PutContent(store, content_2, 1);
+ metisContentStoreInterface_PutContent(store, content_3, 1);
+
+ _MetisLRUContentStore *internalStore = (_MetisLRUContentStore *) metisContentStoreInterface_GetPrivateData(store);
+ _MetisLRUContentStoreStats *stats = &internalStore->stats;
+
+ // Capacity is 1, so we should never grow bigger than that.
+ assertTrue(metisContentStoreInterface_GetObjectCount(store) == 1, "Wrong objectCount. Expected %u, got %zu", 1, metisContentStoreInterface_GetObjectCount(store));
+
+ assertTrue(stats->countAdds == 3, "Wrong countAdds, expected %u got %" PRIu64, 2,
+ stats->countAdds);
+ assertTrue(stats->countLruEvictions == 2, "Wrong countLruEvictions, expected %u got %" PRIu64, 1, stats->countLruEvictions);
+ assertTrue(metisLruList_Length(internalStore->lru) == 1, "Wrong metisLruList_Length, expected %u got %zu", 1,
+ metisLruList_Length(internalStore->lru));
+
+ metisContentStoreInterface_Release(&store);
+ metisLogger_Release(&logger);
+ metisMessage_Release(&content_1);
+ metisMessage_Release(&content_2);
+ metisMessage_Release(&content_3);
+}
+
+LONGBOW_TEST_CASE(Global, metisLRUContentStore_Save_ExpiredContent)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+
+ size_t capacity = 1;
+ MetisContentStoreInterface *store = _createLRUContentStore(capacity);
+
+ 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);
+
+ metisMessage_SetRecommendedCacheTimeTicks(object_1, 50);
+
+ assertFalse(metisContentStoreInterface_PutContent(store, object_1, 51), "Should not be able to insert content past its recommended cache time");
+ assertTrue(metisContentStoreInterface_GetObjectCount(store) == 0, "Wrong objectCount. Expected 0, got %zu", metisContentStoreInterface_GetObjectCount(store));
+
+ metisMessage_SetExpiryTimeTicks(object_2, 100);
+
+ assertFalse(metisContentStoreInterface_PutContent(store, object_2, 101), "Should not be able to insert content past its expiry time");
+ assertTrue(metisContentStoreInterface_GetObjectCount(store) == 0, "Wrong objectCount. Expected 0, got %zu", metisContentStoreInterface_GetObjectCount(store));
+
+ metisContentStoreInterface_Release(&store);
+ metisLogger_Release(&logger);
+ metisMessage_Release(&object_1);
+ metisMessage_Release(&object_2);
+}
+
+
+LONGBOW_TEST_CASE(Global, metisLRUContentStore_Save_WithEvictionByExpiryTime)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+
+ size_t capacity = 1;
+ MetisContentStoreInterface *store = _createLRUContentStore(capacity);
+
+ 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);
+
+ uint64_t currentMetisTime = 150;
+ uint64_t expiryTime = 200;
+
+ metisMessage_SetExpiryTimeTicks(object_1, expiryTime);
+
+ // This should add the object, as currentMetisTime is less than expiry or RCT.
+ metisContentStoreInterface_PutContent(store, object_1, currentMetisTime);
+ assertTrue(metisContentStoreInterface_GetObjectCount(store) == 1, "Wrong objectCount. Expected 1, got %zu", metisContentStoreInterface_GetObjectCount(store));
+
+ // No expiry time.
+ metisContentStoreInterface_PutContent(store, object_2, expiryTime + 10); // Add this one after expiration of first one.
+
+ _MetisLRUContentStore *internalStore = (_MetisLRUContentStore *) metisContentStoreInterface_GetPrivateData(store);
+ _MetisLRUContentStoreStats *stats = &internalStore->stats;
+
+ // Capacity is 1, so we should never grow bigger than that.
+ assertTrue(metisContentStoreInterface_GetObjectCount(store) == 1, "Wrong objectCount. Expected 1, got %zu", metisContentStoreInterface_GetObjectCount(store));
+
+ assertTrue(stats->countAdds == 2, "Wrong countAdds, expected %u got %" PRIu64, 2,
+ stats->countAdds);
+ assertTrue(stats->countExpiryEvictions == 1, "Wrong countLruEvictions, expected %u got %" PRIu64, 1, stats->countLruEvictions);
+ assertTrue(metisLruList_Length(internalStore->lru) == 1, "Wrong metisLruList_Length, expected 1 got %zu",
+ metisLruList_Length(internalStore->lru));
+ assertTrue(metisContentStoreInterface_GetObjectCount(store) == 1, "Expected a store count of 1");
+
+ metisContentStoreInterface_Release(&store);
+ metisLogger_Release(&logger);
+ metisMessage_Release(&object_1);
+ metisMessage_Release(&object_2);
+}
+
+LONGBOW_TEST_CASE(Global, metisLRUContentStore_Save_WithEvictionByRCT)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+
+ size_t capacity = 1;
+ MetisContentStoreInterface *store = _createLRUContentStore(capacity);
+
+ 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);
+
+
+ uint64_t recommendedCacheTime = 1000;
+
+ metisMessage_SetRecommendedCacheTimeTicks(object_1, recommendedCacheTime);
+ metisContentStoreInterface_PutContent(store, object_1, recommendedCacheTime - 100); // Add it.
+
+ assertTrue(metisContentStoreInterface_GetObjectCount(store) == 1, "Wrong objectCount. Expected 1, got %zu",
+ metisContentStoreInterface_GetObjectCount(store));
+
+ metisContentStoreInterface_PutContent(store, object_2, recommendedCacheTime + 1); // Add this one after the first one's RCT.
+
+ _MetisLRUContentStore *internalStore = (_MetisLRUContentStore *) metisContentStoreInterface_GetPrivateData(store);
+ _MetisLRUContentStoreStats *stats = &internalStore->stats;
+
+ // Capacity is 1, so we should never grow bigger than that.
+ assertTrue(metisContentStoreInterface_GetObjectCount(store) == 1, "Wrong objectCount. Expected 1, got %zu",
+ metisContentStoreInterface_GetObjectCount(store));
+
+ assertTrue(stats->countAdds == 2, "Wrong countAdds, expected %u got %" PRIu64, 2,
+ stats->countAdds);
+ assertTrue(stats->countExpiryEvictions == 0, "Wrong countLruEvictions, expected 1got %" PRIu64, stats->countLruEvictions);
+ assertTrue(stats->countRCTEvictions == 1, "Wrong countLruEvictions, expected 1 got %" PRIu64, stats->countLruEvictions);
+
+ assertTrue(metisLruList_Length(internalStore->lru) == 1, "Wrong metisLruList_Length, expected 1 got %zu", metisLruList_Length(internalStore->lru));
+ assertTrue(metisContentStoreInterface_GetObjectCount(store) == 1, "Expected a store count of 1");
+
+ metisContentStoreInterface_Release(&store);
+ metisLogger_Release(&logger);
+ metisMessage_Release(&object_1);
+ metisMessage_Release(&object_2);
+}
+
+LONGBOW_TEST_CASE(Global, metisLRUContentStore_Save_ZeroCapacity)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+
+ size_t capacity = 0;
+ MetisContentStoreInterface *store = _createLRUContentStore(capacity);
+
+ MetisMessage *object_1 = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject,
+ sizeof(metisTestDataV0_EncodedObject), 1, 2, logger);
+ bool success = metisContentStoreInterface_PutContent(store, object_1, 1);
+ assertFalse(success, "Should have returned failure with 0 capacity object store saving something");
+
+ metisMessage_Release(&object_1);
+ metisContentStoreInterface_Release(&store);
+ metisLogger_Release(&logger);
+}
+
+
+LONGBOW_TEST_CASE(Global, metisLRUContentStore_Save_CapacityLimit)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+
+ size_t capacity = 5;
+ MetisContentStoreInterface *store = _createLRUContentStore(capacity);
+
+ for (int i = 1; i < capacity * 2; i++) {
+ int offsetOfNameInEncodedObject = metisTestDataV0_EncodedObject_name.offset + 4;
+
+ MetisMessage *object = _createUniqueMetisMessage(logger, i,
+ metisTestDataV0_EncodedObject,
+ sizeof(metisTestDataV0_EncodedObject),
+ offsetOfNameInEncodedObject);
+
+ bool success = metisContentStoreInterface_PutContent(store, object, 1);
+
+ assertTrue(success, "Unexpectedly failed to add entry to ContentStore");
+
+ if (i < metisContentStoreInterface_GetObjectCapacity(store)) {
+ assertTrue(metisContentStoreInterface_GetObjectCount(store) == i, "Unexpected value for metisContentStoreInterface_objectCount");
+ } else {
+ assertTrue(metisContentStoreInterface_GetObjectCount(store) == metisContentStoreInterface_GetObjectCapacity(store),
+ "Unexpected value (%zu) for metisContentStoreInterface_objectCount (%zu)",
+ metisContentStoreInterface_GetObjectCount(store), metisContentStoreInterface_GetObjectCapacity(store));
+ }
+
+ if (success) {
+ metisMessage_Release(&object);
+ }
+ }
+ metisLogger_Release(&logger);
+ metisContentStoreInterface_Release(&store);
+}
+
+LONGBOW_TEST_CASE(Global, metisLRUContentStore_Save_DuplicateHash)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ MetisLogger *logger = metisLogger_Create(reporter, parcClock_Wallclock());
+ parcLogReporter_Release(&reporter);
+
+ size_t capacity = 5;
+ MetisContentStoreInterface *store = _createLRUContentStore(capacity);
+
+ MetisMessage *object_1 = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject,
+ sizeof(metisTestDataV0_EncodedObject), 1, 2, logger);
+
+
+ bool success = metisContentStoreInterface_PutContent(store, object_1, 1);
+ assertTrue(success, "Expected to add object_1 to store");
+
+ for (int i = 0; i < 10; i++) {
+ MetisMessage *object_1_dup = metisMessage_CreateFromArray(metisTestDataV0_EncodedObject,
+ sizeof(metisTestDataV0_EncodedObject), 1, 2, logger);
+
+ success = metisContentStoreInterface_PutContent(store, object_1_dup, 1l);
+
+ assertFalse(success, "Unexpectedly added duplicated entry to ContentStore");
+
+ assertTrue(metisContentStoreInterface_GetObjectCount(store) == 1, "ObjectCount should be 1");
+
+ metisMessage_Release(&object_1_dup);
+ }
+
+ metisMessage_Release(&object_1);
+ metisContentStoreInterface_Release(&store);
+ metisLogger_Release(&logger);
+}
+
+// ============================================================================
+
+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_LRUContentStore);
+ int exitStatus = longBowMain(argc, argv, testRunner, NULL);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}