LONGBOW_TEST_CASE(Local, _athenaLRUContentStore_PutManyContentObjects) { AthenaLRUContentStore *impl = _createLRUContentStore(); PARCBuffer *payload = parcBuffer_Allocate(1200); int numEntriesToPut = 100; for (int i = 0; i < numEntriesToPut; i++) { // Re-use the payload per contentObject, though the store will think each is seperate (for size calculations) CCNxContentObject *contentObject = _createContentObject("lci:/boose/roo/pie", i, payload); bool status = _athenaLRUContentStore_PutContentObject(impl, contentObject); assertTrue(status, "Expected CO %d to be put in to the store", i); ccnxContentObject_Release(&contentObject); } assertTrue(impl->numEntries == numEntriesToPut, "Expected the numbe of entries put in the store to match"); // Now put the same ones (by name) again. These should kick out the old ones. for (int i = 0; i < numEntriesToPut; i++) { // Re-use the payload per contentObject, though the store will think each is seperate (for size calculations) CCNxContentObject *contentObject = _createContentObject("lci:/boose/roo/pie", i, payload); bool status = _athenaLRUContentStore_PutContentObject(impl, contentObject); assertTrue(status, "Expected CO %d to be put in to the store", i); ccnxContentObject_Release(&contentObject); } assertTrue(impl->numEntries == numEntriesToPut, "Expected the numbe of entries put in the store to match"); parcBuffer_Release(&payload); athenaLRUContentStore_Display(impl, 0); _athenaLRUContentStore_Release((AthenaContentStoreImplementation *) &impl); }
/** * Given a CCNxName, a directory path, and a requested chunk number, create a directory listing and return the specified * chunk of the directory listing as the payload of a newly created CCNxContentObject. * The new CCnxContentObject must eventually be released by calling ccnxContentObject_Release(). * * @param [in] name The CCNxName to use when creating the new CCNxContentObject. * @param [in] directoryPath The directory whose contents are being listed. * @param [in] requestedChunkNumber The number of the requested chunk from the complete directory listing. * * @return A new CCNxContentObject instance containing the request chunk of the directory listing. */ static CCNxContentObject * _createListResponse(CCNxName *name, const char *directoryPath, uint64_t requestedChunkNumber) { CCNxContentObject *result = NULL; PARCBuffer *directoryList = tutorialFileIO_CreateDirectoryListing(directoryPath); uint64_t totalChunksInDirList = _getNumberOfChunksRequired(parcBuffer_Limit(directoryList), tutorialCommon_ChunkSize); if (requestedChunkNumber < totalChunksInDirList) { // Set the buffer's position to the start of the desired chunk. parcBuffer_SetPosition(directoryList, (requestedChunkNumber * tutorialCommon_ChunkSize)); // See if we have more than 1 chunk's worth of data to in the buffer. If so, set the buffer's limit // to the end of the chunk. size_t chunkLen = parcBuffer_Remaining(directoryList); if (chunkLen > tutorialCommon_ChunkSize) { parcBuffer_SetLimit(directoryList, parcBuffer_Position(directoryList) + tutorialCommon_ChunkSize); } printf("tutorialServer: Responding to 'list' command with chunk %ld/%ld\n", (unsigned long) requestedChunkNumber, (unsigned long) totalChunksInDirList); // Calculate the final chunk number uint64_t finalChunkNumber = (totalChunksInDirList > 0) ? totalChunksInDirList - 1 : 0; // the final chunk, 0-based // At this point, dirListBuf has its position and limit set to the beginning and end of the // specified chunk. result = _createContentObject(name, directoryList, finalChunkNumber); } parcBuffer_Release(&directoryList); return result; }
/** * Given a CCNxName, a directory path, a file name, and a requested chunk number, return a new CCNxContentObject * with that CCNxName and containing the specified chunk of the file. The new CCNxContentObject will also * contain the number of the last chunk required to transfer the complete file. Note that the last chunk of the * file being retrieved is calculated each time we retrieve a chunk so the file can be growing in size as we * transfer it. * The new CCnxContentObject must eventually be released by calling ccnxContentObject_Release(). * * @param [in] name The CCNxName to use when creating the new CCNxContentObject. * @param [in] directoryPath The directory in which to find the specified file. * @param [in] fileName The name of the file. * @param [in] requestedChunkNumber The number of the requested chunk from the file. * * @return A new CCNxContentObject instance containing the request chunk of the specified file, or NULL if * the file did not exist or was otherwise unavailable. */ static CCNxContentObject * _createFetchResponse(const CCNxName *name, const char *directoryPath, const char *fileName, uint64_t requestedChunkNumber) { CCNxContentObject *result = NULL; uint64_t finalChunkNumber = 0; // Combine the directoryPath and fileName into the full path name of the desired file size_t filePathBufferSize = strlen(fileName) + strlen(directoryPath) + 2; // +2 for '/' and trailing null. char *fullFilePath = parcMemory_Allocate(filePathBufferSize); assertNotNull(fullFilePath, "parcMemory_Allocate(%zu) returned NULL", filePathBufferSize); snprintf(fullFilePath, filePathBufferSize, "%s/%s", directoryPath, fileName); // Make sure the file exists and is accessible before creating a ContentObject response. if (tutorialFileIO_IsFileAvailable(fullFilePath)) { // Since the file's length can change (e.g. if it is being written to while we're fetching // it), the final chunk number can change between requests for content chunks. So, update // it each time this function is called. finalChunkNumber = _getFinalChunkNumberOfFile(fullFilePath, tutorialCommon_ChunkSize); // Get the actual contents of the specified chunk of the file. PARCBuffer *payload = tutorialFileIO_GetFileChunk(fullFilePath, tutorialCommon_ChunkSize, requestedChunkNumber); if (payload != NULL) { result = _createContentObject(name, payload, finalChunkNumber); parcBuffer_Release(&payload); } } parcMemory_Deallocate((void **) &fullFilePath); return result; // Could be NULL if there was no payload }
LONGBOW_TEST_CASE(Local, putTooBig) { AthenaLRUContentStoreConfig config; config.capacityInMB = 1; AthenaLRUContentStore *impl = _athenaLRUContentStore_Create(&config); size_t payloadSize = 2 * 1024 * 1024; // 2M PARCBuffer *payload = parcBuffer_Allocate(payloadSize); CCNxContentObject *content = _createContentObject("lci:/this/is/content", 10, payload); assertNotNull(content, "Expected to allocated a content object"); bool status = _athenaLRUContentStore_PutContentObject(impl, content); assertFalse(status, "Expected insertion of too large a content object to fail."); ccnxContentObject_Release(&content); parcBuffer_Release(&payload); // Make sure that the contentobjects were added, but that the size didn't grow past the capacity assertTrue(impl->currentSizeInBytes == 0, "expected the current store size to be 0."); _athenaLRUContentStore_Release((AthenaContentStoreImplementation *) &impl); }
LONGBOW_TEST_CASE(Local, putContentAndEnforceCapacity) { AthenaLRUContentStore *impl = _createLRUContentStore(); size_t lastSizeOfStore = 0; size_t payloadSize = 100 * 1024; _athenaLRUContentStore_SetCapacity(impl, 1); // set to 1 MB, or ~10 of our payloads PARCBuffer *payload = parcBuffer_Allocate(payloadSize); // 1M buffer int i; for (i = 0; i < 20; i++) { // Add more than 10 items. CCNxContentObject *content = _createContentObject("lci:/this/is/content", i, payload); assertNotNull(content, "Expected to allocated a content object"); bool status = _athenaLRUContentStore_PutContentObject(impl, content); assertTrue(status, "Expected to be able to insert content"); assertTrue(impl->currentSizeInBytes > lastSizeOfStore, "expected store size in bytes to grow"); ccnxContentObject_Release(&content); } // Make sure that the contentobjects were added, but that the size didn't grow past the capacity assertTrue(impl->currentSizeInBytes < (11 * payloadSize), "expected the current store size to be less than 11 x payload size"); assertTrue(impl->currentSizeInBytes >= (10 * payloadSize), "expected the current store size to be roughly 10 x payload size"); parcBuffer_Release(&payload); _athenaLRUContentStore_Release((AthenaContentStoreImplementation *) &impl); }
LONGBOW_TEST_CASE(Local, _athenaLRUContentStoreEntry_CreateRelease) { CCNxContentObject *contentObject = _createContentObject("lci:/boose/roo/pie", 0, NULL); _AthenaLRUContentStoreEntry *entry = _athenaLRUContentStoreEntry_Create(contentObject); _athenaLRUContentStoreEntry_Release(&entry); ccnxContentObject_Release(&contentObject); }
LONGBOW_TEST_CASE(Global, putContent) { AthenaLRUContentStoreConfig config; config.capacityInMB = 10; AthenaContentStore *store = athenaContentStore_Create(&AthenaContentStore_LRUImplementation, &config); PARCBuffer *payload = parcBuffer_WrapCString("this is a payload"); CCNxContentObject *contentObject = _createContentObject("lci:/cakes/and/pies", 0, payload); parcBuffer_Release(&payload); ccnxContentObject_SetExpiryTime(contentObject, 100); athenaContentStore_PutContentObject(store, contentObject); athenaContentStore_Release(&store); ccnxContentObject_Release(&contentObject); }
LONGBOW_TEST_CASE(EmptyImplementation, booleanApiFunctions) { AthenaContentStore *store = athenaContentStore_Create(&EmptyContentStoreImplementation, NULL); CCNxContentObject *contentObject = _createContentObject("lci:/dogs/are/better/than/cats", 10, NULL); CCNxName *name = ccnxName_CreateFromURI("lci:/pie/is/always/good"); CCNxInterest *interest = ccnxInterest_CreateSimple(name); //athena_EncodeMessage(interest); AthenaContentStore *ref = athenaContentStore_Acquire(store); athenaContentStore_Release(&ref); assertFalse(athenaContentStore_PutContentObject(store, contentObject), "Expected false from PutContentObject"); assertFalse(athenaContentStore_GetMatch(store, interest), "Expected false from GetMatch"); assertFalse(athenaContentStore_SetCapacity(store, 1), "Expected false from SetCapacity"); assertFalse(athenaContentStore_RemoveMatch(store, name, NULL, NULL), "Expected false from RemoveMatch"); ccnxName_Release(&name); ccnxInterest_Release(&interest); ccnxContentObject_Release(&contentObject); athenaContentStore_Release(&store); }
LONGBOW_TEST_CASE(Local, _athenaLRUContentStore_PutContentObject) { AthenaLRUContentStore *impl = _createLRUContentStore(); PARCBuffer *payload = parcBuffer_Allocate(1200); CCNxContentObject *contentObject = _createContentObject("lci:/boose/roo/pie", 10, NULL); parcBuffer_Release(&payload); bool status = _athenaLRUContentStore_PutContentObject(impl, contentObject); assertTrue(status, "Expected to put content into the store"); // This should replace the existing entry. status = _athenaLRUContentStore_PutContentObject(impl, contentObject); assertTrue(status, "Expected to put content into the store a second time"); assertTrue(impl->numEntries == 1, "Expected 1 entry in the store (after implicit removal of original entry"); assertTrue(impl->stats.numAdds == 2, "Expected stats to show 2 adds"); ccnxContentObject_Release(&contentObject); _athenaLRUContentStore_Release((AthenaContentStoreImplementation *) &impl); }
LONGBOW_TEST_CASE(Local, _athenaLRUContentStore_PutLRUContentStoreEntry) { AthenaLRUContentStore *impl = _createLRUContentStore(); PARCBuffer *payload = parcBuffer_Allocate(1200); CCNxContentObject *contentObject = _createContentObject("lci:/boose/roo/pie", 10, NULL); parcBuffer_Release(&payload); _AthenaLRUContentStoreEntry *entry = _athenaLRUContentStoreEntry_Create(contentObject); ccnxContentObject_Release(&contentObject); entry->expiryTime = 10000; entry->contentObjectHash = parcBuffer_WrapCString("object hash buffer"); entry->keyId = parcBuffer_WrapCString("key id buffer"); entry->hasContentObjectHash = true; entry->hasKeyId = true; bool status = _athenaLRUContentStore_PutLRUContentStoreEntry(impl, entry); assertTrue(status, "Expected to put content into the store"); assertTrue(status, "Expected to put content into the store a second time"); assertTrue(impl->numEntries == 1, "Expected 1 entry in the store"); assertTrue(impl->stats.numAdds == 1, "Expected stats to show 1 adds"); _athenaLRUContentStore_PurgeContentStoreEntry(impl, entry); assertTrue(impl->numEntries == 0, "Expected 0 entries in the store"); parcBuffer_Release(&entry->keyId); parcBuffer_Release(&entry->contentObjectHash); _athenaLRUContentStoreEntry_Release(&entry); _athenaLRUContentStore_Release((AthenaContentStoreImplementation *) &impl); }