diff options
Diffstat (limited to 'metis/ccnx/forwarder/metis/io/test/test_metis_StreamConnection.c')
-rw-r--r-- | metis/ccnx/forwarder/metis/io/test/test_metis_StreamConnection.c | 767 |
1 files changed, 767 insertions, 0 deletions
diff --git a/metis/ccnx/forwarder/metis/io/test/test_metis_StreamConnection.c b/metis/ccnx/forwarder/metis/io/test/test_metis_StreamConnection.c new file mode 100644 index 00000000..5ae50bcd --- /dev/null +++ b/metis/ccnx/forwarder/metis/io/test/test_metis_StreamConnection.c @@ -0,0 +1,767 @@ +/* + * 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_StreamConnection.c" +#include <LongBow/unit-test.h> +#include <parc/algol/parc_SafeMemory.h> +#include <parc/logging/parc_LogReporterTextStdout.h> + +#include <ccnx/forwarder/metis/tlv/metis_Tlv.h> +#include <ccnx/forwarder/metis/testdata/metis_TestDataV0.h> + +// inet_pton +#include <arpa/inet.h> + +#include <fcntl.h> + +#include <stdio.h> + +#ifndef INPORT_ANY +#define INPORT_ANY 0 +#endif + +// we hand-code some packets in the unit tests +typedef struct __attribute__ ((__packed__)) metis_tlv_fixed_header { + uint8_t version; + uint8_t packetType; + uint16_t payloadLength; + uint16_t reserved; + uint16_t headerLength; +} _MetisTlvFixedHeaderV0; + + +LONGBOW_TEST_RUNNER(metis_StreamConnection) +{ + // 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_StreamConnection) +{ + 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_StreamConnection) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// ================================================================================ +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, metisStreamConnection_Create); + LONGBOW_RUN_TEST_CASE(Global, metisStreamConnection_OpenConnection); +} + +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, metisStreamConnection_Create) +{ + int fd = socket(AF_INET, SOCK_STREAM, 0); + struct sockaddr_in addr_local; + addr_local.sin_addr.s_addr = htonl(0x01020304); + addr_local.sin_family = AF_INET; + addr_local.sin_port = htons(56); + + struct sockaddr_in addr_remote; + addr_remote.sin_addr.s_addr = htonl(0x0708090A); + addr_remote.sin_family = AF_INET; + addr_remote.sin_port = htons(12); + + CPIAddress *local = cpiAddress_CreateFromInet(&addr_local); + CPIAddress *remote = cpiAddress_CreateFromInet(&addr_remote); + MetisAddressPair *pair = metisAddressPair_Create(local, remote); + + MetisForwarder *metis = metisForwarder_Create(NULL); + metisLogger_SetLogLevel(metisForwarder_GetLogger(metis), MetisLoggerFacility_IO, PARCLogLevel_Debug); + MetisIoOperations *ops = metisStreamConnection_AcceptConnection(metis, fd, pair, false); + + ops->destroy(&ops); + metisDispatcher_RunDuration(metisForwarder_GetDispatcher(metis), &((struct timeval) { 0, 10000 })); + + metisForwarder_Destroy(&metis); + close(fd); + cpiAddress_Destroy(&local); + cpiAddress_Destroy(&remote); + assertTrue(parcSafeMemory_Outstanding() == 0, "Got memory imbalance: %u", parcSafeMemory_Outstanding()); +} + +static int +listenToInet(struct sockaddr_in *server) +{ + int fd = socket(PF_INET, SOCK_STREAM, 0); + assertFalse(fd < 0, "error on bind: (%d) %s", errno, strerror(errno)); + + // Set non-blocking flag + int flags = fcntl(fd, F_GETFL, NULL); + assertTrue(flags != -1, "fcntl failed to obtain file descriptor flags (%d)\n", errno); + int failure = fcntl(fd, F_SETFL, flags | O_NONBLOCK); + assertFalse(failure, "fcntl failed to set file descriptor flags (%d)\n", errno); + + failure = bind(fd, (struct sockaddr *) server, sizeof(struct sockaddr_in)); + assertFalse(failure, "error on bind: (%d) %s", errno, strerror(errno)); + + failure = listen(fd, 16); + assertFalse(failure, "error on listen: (%d) %s", errno, strerror(errno)); + + return fd; +} + +LONGBOW_TEST_CASE(Global, metisStreamConnection_OpenConnection) +{ + MetisForwarder *metis = metisForwarder_Create(NULL); + + struct sockaddr_in serverAddr; + memset(&serverAddr, 0, sizeof(serverAddr)); + serverAddr.sin_family = PF_INET; + serverAddr.sin_port = INPORT_ANY; + inet_pton(AF_INET, "127.0.0.1", &(serverAddr.sin_addr)); + + int serverSocket = listenToInet(&serverAddr); + socklen_t x = sizeof(serverAddr); + int failure = getsockname(serverSocket, (struct sockaddr *) &serverAddr, &x); + assertFalse(failure, "error on getsockname: (%d) %s", errno, strerror(errno)); + + struct sockaddr_in localAddr; + memset(&localAddr, 0, sizeof(localAddr)); + localAddr.sin_family = PF_INET; + localAddr.sin_addr.s_addr = INADDR_ANY; + localAddr.sin_port = INPORT_ANY; + + CPIAddress *local = cpiAddress_CreateFromInet(&localAddr); + + // change from 0.0.0.0 to 127.0.0.1 + inet_pton(AF_INET, "127.0.0.1", &(serverAddr.sin_addr)); + + CPIAddress *remote = cpiAddress_CreateFromInet(&serverAddr); + MetisAddressPair *pair = metisAddressPair_Create(local, remote); + cpiAddress_Destroy(&local); + cpiAddress_Destroy(&remote); + + MetisIoOperations *ops = metisStreamConnection_OpenConnection(metis, pair, false); + assertNotNull(ops, "Got null ops from metisStreamConnection_OpenConnection"); + metisDispatcher_RunDuration(metisForwarder_GetDispatcher(metis), &((struct timeval) { 0, 10000 })); + + ops->destroy(&ops); + metisForwarder_Destroy(&metis); +} + +// ======================================================================= + +// ================================================================================== + +LONGBOW_TEST_FIXTURE(Local) +{ + LONGBOW_RUN_TEST_CASE(Local, conn_eventcb_Connected); + LONGBOW_RUN_TEST_CASE(Local, conn_eventcb_EOF); + LONGBOW_RUN_TEST_CASE(Local, conn_eventcb_ERROR); + + LONGBOW_RUN_TEST_CASE(Local, conn_readcb); + LONGBOW_RUN_TEST_CASE(Local, metisStreamConnection_Equals); + LONGBOW_RUN_TEST_CASE(Local, metisStreamConnection_GetAddress); + LONGBOW_RUN_TEST_CASE(Local, metisStreamConnection_GetAddressPair); + LONGBOW_RUN_TEST_CASE(Local, metisStreamConnection_GetConnectionId); + LONGBOW_RUN_TEST_CASE(Local, metisStreamConnection_HashCode); + LONGBOW_RUN_TEST_CASE(Local, metisStreamConnection_IsUp); + LONGBOW_RUN_TEST_CASE(Local, metisStreamConnection_Send); + LONGBOW_RUN_TEST_CASE(Local, metisStreamConnection_GetConnectionType); + LONGBOW_RUN_TEST_CASE(Local, printConnection); + LONGBOW_RUN_TEST_CASE(Local, readMessage); + LONGBOW_RUN_TEST_CASE(Local, setConnectionState); + LONGBOW_RUN_TEST_CASE(Local, single_read_ZeroNextMessageLength); + LONGBOW_RUN_TEST_CASE(Local, single_read_PartialRead); + LONGBOW_RUN_TEST_CASE(Local, single_read_FullRead); + LONGBOW_RUN_TEST_CASE(Local, startNewMessage); +} + +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, conn_eventcb_Connected) +{ + int fds[2]; + int failure = socketpair(AF_LOCAL, SOCK_STREAM, 0, fds); + assertFalse(failure, "Error socketpair: (%d) %s", errno, strerror(errno)); + + struct sockaddr_in addr_local; + addr_local.sin_addr.s_addr = htonl(0x01020304); + addr_local.sin_family = AF_INET; + addr_local.sin_port = htons(56); + + struct sockaddr_in addr_remote; + addr_remote.sin_addr.s_addr = htonl(0x0708090A); + addr_remote.sin_family = AF_INET; + addr_remote.sin_port = htons(12); + + CPIAddress *local = cpiAddress_CreateFromInet(&addr_local); + CPIAddress *remote = cpiAddress_CreateFromInet(&addr_remote); + MetisAddressPair *pair = metisAddressPair_Create(local, remote); + + MetisForwarder *metis = metisForwarder_Create(NULL); + MetisIoOperations *ops = metisStreamConnection_AcceptConnection(metis, fds[0], pair, false); + _MetisStreamState *stream = (_MetisStreamState *) metisIoOperations_GetClosure(ops); + + stream->isUp = false; + + // ---- the actual test + _conn_eventcb(stream->bufferEventVector, PARCEventQueueEventType_Connected, ops); + assertTrue(stream->isUp, "PARCEventQueueEventType_Connected did not trigger stream to up state"); + // ---- + + ops->destroy(&ops); + metisForwarder_Destroy(&metis); + close(fds[0]); + close(fds[1]); + cpiAddress_Destroy(&local); + cpiAddress_Destroy(&remote); +} + +LONGBOW_TEST_CASE(Local, conn_eventcb_EOF) +{ + int fds[2]; + int failure = socketpair(AF_LOCAL, SOCK_STREAM, 0, fds); + assertFalse(failure, "Error socketpair: (%d) %s", errno, strerror(errno)); + + struct sockaddr_in addr_local; + addr_local.sin_addr.s_addr = htonl(0x01020304); + addr_local.sin_family = AF_INET; + addr_local.sin_port = htons(56); + + struct sockaddr_in addr_remote; + addr_remote.sin_addr.s_addr = htonl(0x0708090A); + addr_remote.sin_family = AF_INET; + addr_remote.sin_port = htons(12); + + CPIAddress *local = cpiAddress_CreateFromInet(&addr_local); + CPIAddress *remote = cpiAddress_CreateFromInet(&addr_remote); + MetisAddressPair *pair = metisAddressPair_Create(local, remote); + + MetisForwarder *metis = metisForwarder_Create(NULL); + MetisIoOperations *ops = metisStreamConnection_AcceptConnection(metis, fds[0], pair, false); + _MetisStreamState *stream = (_MetisStreamState *) metisIoOperations_GetClosure(ops); + + stream->isUp = true; + + // ---- the actual test + _conn_eventcb(stream->bufferEventVector, PARCEventQueueEventType_EOF, ops); + assertFalse(stream->isUp, "PARCEventQueueEventType_EOF did not trigger stream to down state"); + // ---- + + ops->destroy(&ops); + metisForwarder_Destroy(&metis); + close(fds[0]); + close(fds[1]); + cpiAddress_Destroy(&local); + cpiAddress_Destroy(&remote); +} + +LONGBOW_TEST_CASE(Local, conn_eventcb_ERROR) +{ + int fds[2]; + int failure = socketpair(AF_LOCAL, SOCK_STREAM, 0, fds); + assertFalse(failure, "Error socketpair: (%d) %s", errno, strerror(errno)); + + struct sockaddr_in addr_local; + addr_local.sin_addr.s_addr = htonl(0x01020304); + addr_local.sin_family = AF_INET; + addr_local.sin_port = htons(56); + + struct sockaddr_in addr_remote; + addr_remote.sin_addr.s_addr = htonl(0x0708090A); + addr_remote.sin_family = AF_INET; + addr_remote.sin_port = htons(12); + + CPIAddress *local = cpiAddress_CreateFromInet(&addr_local); + CPIAddress *remote = cpiAddress_CreateFromInet(&addr_remote); + MetisAddressPair *pair = metisAddressPair_Create(local, remote); + + MetisForwarder *metis = metisForwarder_Create(NULL); + MetisIoOperations *ops = metisStreamConnection_AcceptConnection(metis, fds[0], pair, false); + _MetisStreamState *stream = (_MetisStreamState *) metisIoOperations_GetClosure(ops); + + stream->isUp = true; + + // ---- the actual test + _conn_eventcb(stream->bufferEventVector, PARCEventQueueEventType_Error, ops); + assertFalse(stream->isUp, "PARCEventQueueEventType_Error did not trigger stream to down state"); + // ---- + + ops->destroy(&ops); + metisForwarder_Destroy(&metis); + close(fds[0]); + close(fds[1]); + cpiAddress_Destroy(&local); + cpiAddress_Destroy(&remote); +} + +LONGBOW_TEST_CASE(Local, conn_readcb) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Local, metisStreamConnection_Equals) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Local, metisStreamConnection_GetAddress) +{ + int fd = socket(AF_INET, SOCK_STREAM, 0); + struct sockaddr_in addr_local; + addr_local.sin_addr.s_addr = htonl(0x01020304); + addr_local.sin_family = AF_INET; + addr_local.sin_port = htons(56); + + struct sockaddr_in addr_remote; + addr_remote.sin_addr.s_addr = htonl(0x0708090A); + addr_remote.sin_family = AF_INET; + addr_remote.sin_port = htons(12); + + CPIAddress *local = cpiAddress_CreateFromInet(&addr_local); + CPIAddress *remote = cpiAddress_CreateFromInet(&addr_remote); + MetisAddressPair *pair = metisAddressPair_Create(local, remote); + + MetisForwarder *metis = metisForwarder_Create(NULL); + MetisIoOperations *ops = metisStreamConnection_AcceptConnection(metis, fd, pair, false); + + const CPIAddress *test_addr = ops->getRemoteAddress(ops); + + assertTrue(cpiAddress_Equals(remote, test_addr), "ops->getAddress incorrect"); + + ops->destroy(&ops); + metisForwarder_Destroy(&metis); + cpiAddress_Destroy(&local); + cpiAddress_Destroy(&remote); + + close(fd); +} + +LONGBOW_TEST_CASE(Local, metisStreamConnection_GetAddressPair) +{ + int fd = socket(AF_INET, SOCK_STREAM, 0); + struct sockaddr_in addr_local; + addr_local.sin_addr.s_addr = htonl(0x01020304); + addr_local.sin_family = AF_INET; + addr_local.sin_port = htons(56); + + struct sockaddr_in addr_remote; + addr_remote.sin_addr.s_addr = htonl(0x0708090A); + addr_remote.sin_family = AF_INET; + addr_remote.sin_port = htons(12); + + CPIAddress *local = cpiAddress_CreateFromInet(&addr_local); + CPIAddress *remote = cpiAddress_CreateFromInet(&addr_remote); + MetisAddressPair *pair = metisAddressPair_Create(local, remote); + + MetisForwarder *metis = metisForwarder_Create(NULL); + MetisIoOperations *ops = metisStreamConnection_AcceptConnection(metis, fd, pair, false); + + const MetisAddressPair *test_pair = ops->getAddressPair(ops); + + assertTrue(metisAddressPair_Equals(pair, test_pair), "ops->getRemoteAddress incorrect"); + + ops->destroy(&ops); + metisForwarder_Destroy(&metis); + cpiAddress_Destroy(&local); + cpiAddress_Destroy(&remote); + + close(fd); +} + +LONGBOW_TEST_CASE(Local, metisStreamConnection_GetConnectionId) +{ + int fd = socket(AF_INET, SOCK_STREAM, 0); + struct sockaddr_in addr_local; + addr_local.sin_addr.s_addr = htonl(0x01020304); + addr_local.sin_family = AF_INET; + addr_local.sin_port = htons(56); + + struct sockaddr_in addr_remote; + addr_remote.sin_addr.s_addr = htonl(0x0708090A); + addr_remote.sin_family = AF_INET; + addr_remote.sin_port = htons(12); + + CPIAddress *local = cpiAddress_CreateFromInet(&addr_local); + CPIAddress *remote = cpiAddress_CreateFromInet(&addr_remote); + MetisAddressPair *pair = metisAddressPair_Create(local, remote); + + MetisForwarder *metis = metisForwarder_Create(NULL); + unsigned truth_connid = metisForwarder_GetNextConnectionId(metis) + 1; + + MetisIoOperations *ops = metisStreamConnection_AcceptConnection(metis, fd, pair, false); + + assertTrue(ops->getConnectionId(ops) == truth_connid, "Got wrong connection id, expected %u got %u", truth_connid, ops->getConnectionId(ops)); + + ops->destroy(&ops); + metisForwarder_Destroy(&metis); + cpiAddress_Destroy(&local); + cpiAddress_Destroy(&remote); + + close(fd); +} + +LONGBOW_TEST_CASE(Local, metisStreamConnection_HashCode) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Local, metisStreamConnection_IsUp) +{ + int fd = socket(AF_INET, SOCK_STREAM, 0); + struct sockaddr_in addr_local; + addr_local.sin_addr.s_addr = htonl(0x01020304); + addr_local.sin_family = AF_INET; + addr_local.sin_port = htons(56); + + struct sockaddr_in addr_remote; + addr_remote.sin_addr.s_addr = htonl(0x0708090A); + addr_remote.sin_family = AF_INET; + addr_remote.sin_port = htons(12); + + CPIAddress *local = cpiAddress_CreateFromInet(&addr_local); + CPIAddress *remote = cpiAddress_CreateFromInet(&addr_remote); + MetisAddressPair *pair = metisAddressPair_Create(local, remote); + + MetisForwarder *metis = metisForwarder_Create(NULL); + MetisIoOperations *ops = metisStreamConnection_AcceptConnection(metis, fd, pair, false); + + assertTrue(ops->isUp(ops), "isUp incorrect, expected true, got false"); + + ops->destroy(&ops); + metisForwarder_Destroy(&metis); + cpiAddress_Destroy(&local); + cpiAddress_Destroy(&remote); + close(fd); +} + +LONGBOW_TEST_CASE(Local, metisStreamConnection_Send) +{ + // StreamConnection_Create needs a socket and address to represent the peer + // we use a socket pair so we can actaully read from it and verify what is sent. + + int fds[2]; + int failure = socketpair(AF_LOCAL, SOCK_STREAM, 0, fds); + assertFalse(failure, "Error socketpair: (%d) %s", errno, strerror(errno)); + + struct sockaddr_in addr_local; + addr_local.sin_addr.s_addr = htonl(0x01020304); + addr_local.sin_family = AF_INET; + addr_local.sin_port = htons(56); + + struct sockaddr_in addr_remote; + addr_remote.sin_addr.s_addr = htonl(0x0708090A); + addr_remote.sin_family = AF_INET; + addr_remote.sin_port = htons(12); + CPIAddress *local = cpiAddress_CreateFromInet(&addr_local); + CPIAddress *remote = cpiAddress_CreateFromInet(&addr_remote); + MetisAddressPair *pair = metisAddressPair_Create(local, remote); + + MetisForwarder *metis = metisForwarder_Create(NULL); + MetisIoOperations *ops = metisStreamConnection_AcceptConnection(metis, fds[0], pair, false); + + // ---------- + // Create a fake message. Send does not care what the message is, it just writes it out. + // We include a real header, but it is not needed. + + char message_str[] = "\x00Once upon a jiffie, in a stack far away, a dangling pointer found its way to the top of the heap."; + _MetisTlvFixedHeaderV0 *hdr = (_MetisTlvFixedHeaderV0 *) message_str; + hdr->payloadLength = htons(92); + hdr->headerLength = htons(0); + + MetisMessage *sendmessage = metisMessage_CreateFromArray((uint8_t *) message_str, sizeof(message_str), 1, 2, metisForwarder_GetLogger(metis)); + + // ---------- + // actually send it + ops->send(ops, NULL, sendmessage); + metisMessage_Release(&sendmessage); + + // ---------- + // turn the handleto crank + metisDispatcher_RunDuration(metisForwarder_GetDispatcher(metis), &((struct timeval) { 0, 10000 })); + + // ---------- + // Now read the result from our end of the socket pair. + + uint8_t read_buffer[1024]; + + // read it and verify + ssize_t read_length = read(fds[1], read_buffer, 1024); + assertTrue(read_length == sizeof(message_str), + "Incorrect read length, expected %zu got %zd: (%d) %s", + sizeof(message_str), read_length, errno, strerror(errno)); + + assertTrue(memcmp(read_buffer, message_str, sizeof(message_str)) == 0, "read_buffer does not match message_str"); + + // ---------- + // hurray, no messages where harmed in this experiment + + ops->destroy(&ops); + metisForwarder_Destroy(&metis); + close(fds[0]); + close(fds[1]); + cpiAddress_Destroy(&local); + cpiAddress_Destroy(&remote); +} + +LONGBOW_TEST_CASE(Local, metisStreamConnection_GetConnectionType) +{ + int fd = socket(AF_INET, SOCK_STREAM, 0); + struct sockaddr_in addr_local; + addr_local.sin_addr.s_addr = htonl(0x01020304); + addr_local.sin_family = AF_INET; + addr_local.sin_port = htons(56); + + struct sockaddr_in addr_remote; + addr_remote.sin_addr.s_addr = htonl(0x0708090A); + addr_remote.sin_family = AF_INET; + addr_remote.sin_port = htons(12); + + CPIAddress *local = cpiAddress_CreateFromInet(&addr_local); + CPIAddress *remote = cpiAddress_CreateFromInet(&addr_remote); + MetisAddressPair *pair = metisAddressPair_Create(local, remote); + + MetisForwarder *metis = metisForwarder_Create(NULL); + MetisIoOperations *ops = metisStreamConnection_AcceptConnection(metis, fd, pair, false); + + CPIConnectionType connType = _metisStreamConnection_GetConnectionType(ops); + assertTrue(connType == cpiConnection_TCP, "Wrong connection type expected %d got %d", cpiConnection_TCP, connType); + + ops->destroy(&ops); + metisForwarder_Destroy(&metis); + cpiAddress_Destroy(&local); + cpiAddress_Destroy(&remote); + close(fd); +} + +LONGBOW_TEST_CASE(Local, printConnection) +{ + testUnimplemented("This test is unimplemented"); +} + +LONGBOW_TEST_CASE(Local, readMessage) +{ + char message_str[] = "\x00Once upon a jiffie, in a stack far away, a dangling pointer found its way to the top of the heap."; + _MetisTlvFixedHeaderV0 *hdr = (_MetisTlvFixedHeaderV0 *) message_str; + hdr->payloadLength = htons(92); + hdr->headerLength = htons(0); + + PARCEventBuffer *buff = parcEventBuffer_Create(); + parcEventBuffer_Append(buff, message_str, sizeof(message_str)); + + _MetisStreamState *stream = parcMemory_AllocateAndClear(sizeof(_MetisStreamState)); + assertNotNull(stream, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(_MetisStreamState)); + stream->nextMessageLength = parcEventBuffer_GetLength(buff); + stream->id = 77; + + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + stream->logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + + MetisMessage *message = _readMessage(stream, 444, buff); + + assertNotNull(message, "Got null message from readMessage"); + assertTrue(parcEventBuffer_GetLength(buff) == 0, "Did not drain input buffer, expected 0 got %zu", parcEventBuffer_GetLength(buff)); + //assertTrue(metisMessage_Length(message) == sizeof(message_str), + //"Message length wrong, expected %zu got %zu", + //sizeof(message_str), + //metisMessage_Length(message)); + + metisMessage_Release(&message); + parcEventBuffer_Destroy(&buff); + metisLogger_Release(&stream->logger); + parcMemory_Deallocate((void **) &stream); +} + +LONGBOW_TEST_CASE(Local, setConnectionState) +{ + testUnimplemented("This test is unimplemented"); +} + +/** + * Call like the beignning of a new packet, with stream->nextMessageLength set to 0 + */ +LONGBOW_TEST_CASE(Local, single_read_ZeroNextMessageLength) +{ + PARCEventBuffer *buff = parcEventBuffer_Create(); + + // do it like a short read, only 12 bytes + parcEventBuffer_Append(buff, metisTestDataV0_EncodedInterest, 12); + + MetisForwarder *metis = metisForwarder_Create(NULL); + _MetisStreamState *stream = parcMemory_AllocateAndClear(sizeof(_MetisStreamState)); + assertNotNull(stream, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(_MetisStreamState)); + stream->metis = metis; + stream->nextMessageLength = 0; + stream->id = 77; + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + stream->logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *message = _single_read(buff, stream); + + assertNull(message, "message should be null, its a short read"); + assertTrue(parcEventBuffer_GetLength(buff) == 12, "Should not have drained buffer, expected %d got %zu", 12, parcEventBuffer_GetLength(buff)); + assertTrue(stream->nextMessageLength == sizeof(metisTestDataV0_EncodedInterest), + "NextMessageLength not set correctly, expected %zu got %zu", + sizeof(metisTestDataV0_EncodedInterest), + stream->nextMessageLength); + + parcEventBuffer_Destroy(&buff); + metisLogger_Release(&stream->logger); + parcMemory_Deallocate((void **) &stream); + metisForwarder_Destroy(&metis); +} + +/** + * Call with stream->nextMessageLength set correctly, but not enough bytes in the buffer + */ +LONGBOW_TEST_CASE(Local, single_read_PartialRead) +{ + PARCEventBuffer *buff = parcEventBuffer_Create(); + + // do it like a short read, only 12 bytes + parcEventBuffer_Append(buff, metisTestDataV0_EncodedInterest, 12); + + MetisForwarder *metis = metisForwarder_Create(NULL); + _MetisStreamState *stream = parcMemory_AllocateAndClear(sizeof(_MetisStreamState)); + assertNotNull(stream, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(_MetisStreamState)); + stream->metis = metis; + stream->nextMessageLength = sizeof(metisTestDataV0_EncodedInterest); + stream->id = 77; + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + stream->logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *message = _single_read(buff, stream); + + assertNull(message, "message should be null, its a short read"); + assertTrue(parcEventBuffer_GetLength(buff) == 12, "Should not have drained buffer, expected %d got %zu", 12, parcEventBuffer_GetLength(buff)); + assertTrue(stream->nextMessageLength == sizeof(metisTestDataV0_EncodedInterest), + "NextMessageLength not set correctly, expected %zu got %zu", + sizeof(metisTestDataV0_EncodedInterest), + stream->nextMessageLength); + + parcEventBuffer_Destroy(&buff); + metisLogger_Release(&stream->logger); + parcMemory_Deallocate((void **) &stream); + metisForwarder_Destroy(&metis); +} + +/** + * Call with enough bytes in the buffer to read the whole message + */ +LONGBOW_TEST_CASE(Local, single_read_FullRead) +{ + PARCEventBuffer *buff = parcEventBuffer_Create(); + + // do it like a full read + parcEventBuffer_Append(buff, metisTestDataV0_EncodedInterest, sizeof(metisTestDataV0_EncodedInterest)); + + MetisForwarder *metis = metisForwarder_Create(NULL); + _MetisStreamState *stream = parcMemory_AllocateAndClear(sizeof(_MetisStreamState)); + assertNotNull(stream, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(_MetisStreamState)); + stream->metis = metis; + stream->nextMessageLength = sizeof(metisTestDataV0_EncodedInterest); + stream->id = 77; + PARCLogReporter *reporter = parcLogReporterTextStdout_Create(); + stream->logger = metisLogger_Create(reporter, parcClock_Wallclock()); + parcLogReporter_Release(&reporter); + MetisMessage *message = _single_read(buff, stream); + + assertNotNull(message, "message should not be null, its a short read"); + assertTrue(parcEventBuffer_GetLength(buff) == 0, "Should have drained buffer, expected %d got %zu", 0, parcEventBuffer_GetLength(buff)); + + // should reset the next message length after reading a whole packet + assertTrue(stream->nextMessageLength == 0, + "NextMessageLength not set correctly, expected %u got %zu", + 0, + stream->nextMessageLength); + + metisMessage_Release(&message); + parcEventBuffer_Destroy(&buff); + metisLogger_Release(&stream->logger); + parcMemory_Deallocate((void **) &stream); + metisForwarder_Destroy(&metis); +} + +LONGBOW_TEST_CASE(Local, startNewMessage) +{ + _MetisStreamState *stream = parcMemory_AllocateAndClear(sizeof(_MetisStreamState)); + assertNotNull(stream, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(_MetisStreamState)); + + // add data to the buffer to fake out having read from the network + PARCEventBuffer *buff = parcEventBuffer_Create(); + uint8_t *truth_message = parcMemory_Allocate(100); + assertNotNull(truth_message, "parcMemory_Allocate(%u) returned NULL", 100); + + _MetisTlvFixedHeaderV0 *hdr = (_MetisTlvFixedHeaderV0 *) truth_message; + hdr->version = 0; + hdr->payloadLength = htons(92); + hdr->headerLength = htons(0); + + parcEventBuffer_Append(buff, truth_message, 100); + + stream->nextMessageLength = 0; + + _startNewMessage(stream, buff, 100); + + assertTrue(stream->nextMessageLength == 100, "nextMessageLength wrong, expected %d got %zu", 100, stream->nextMessageLength); + + parcEventBuffer_Destroy(&buff); + parcMemory_Deallocate((void **) &stream); + parcMemory_Deallocate((void **) &truth_message); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(metis_StreamConnection); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} |