LONGBOW_TEST_CASE(Global, athenaTransportLinkModuleUDP_SendReceive)
{
    PARCURI *connectionURI;
    const char *result;
    AthenaTransportLinkAdapter *athenaTransportLinkAdapter = athenaTransportLinkAdapter_Create(_removeLink, NULL);
    assertNotNull(athenaTransportLinkAdapter, "athenaTransportLinkAdapter_Create returned NULL");

    connectionURI = parcURI_Parse("udp://127.0.0.1:40000/Listener/name=UDPListener");
    result = athenaTransportLinkAdapter_Open(athenaTransportLinkAdapter, connectionURI);
    assertTrue(result != NULL, "athenaTransportLinkAdapter_Open failed (%s)", strerror(errno));
    parcURI_Release(&connectionURI);

    connectionURI = parcURI_Parse("udp://127.0.0.1:40000/name=UDP_1");
    result = athenaTransportLinkAdapter_Open(athenaTransportLinkAdapter, connectionURI);
    assertTrue(result != NULL, "athenaTransportLinkAdapter_Open failed (%s)", strerror(errno));
    parcURI_Release(&connectionURI);

    athenaTransportLinkAdapter_Poll(athenaTransportLinkAdapter, 0);

    CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar");
    CCNxMetaMessage *ccnxMetaMessage = ccnxInterest_CreateSimple(name);
    ccnxName_Release(&name);

    PARCBitVector *sendVector = parcBitVector_Create();

    int linkId = athenaTransportLinkAdapter_LinkNameToId(athenaTransportLinkAdapter, "UDP_1");
    parcBitVector_Set(sendVector, linkId);

    athena_EncodeMessage(ccnxMetaMessage);
    PARCBitVector *resultVector;
    resultVector = athenaTransportLinkAdapter_Send(athenaTransportLinkAdapter, ccnxMetaMessage, sendVector);
    assertNotNull(resultVector, "athenaTransportLinkAdapter_Send failed");
    parcBitVector_Release(&resultVector);
    ccnxMetaMessage_Release(&ccnxMetaMessage);
    parcBitVector_Release(&sendVector);

    usleep(1000);

    ccnxMetaMessage = athenaTransportLinkAdapter_Receive(athenaTransportLinkAdapter, &resultVector, 0);
    assertNotNull(resultVector, "athenaTransportLinkAdapter_Receive failed");
    assertTrue(parcBitVector_NumberOfBitsSet(resultVector) == 1, "athenaTransportLinkAdapter_Receive return message with more than one ingress link");
    assertNotNull(ccnxMetaMessage, "athenaTransportLinkAdapter_Receive failed to provide message");
    parcBitVector_Release(&resultVector);
    ccnxMetaMessage_Release(&ccnxMetaMessage);

    // Close one end of the connection and send a message from the other.
    int closeResult = athenaTransportLinkAdapter_CloseByName(athenaTransportLinkAdapter, "UDPListener");
    assertTrue(closeResult == 0, "athenaTransportLinkAdapter_CloseByName failed (%s)", strerror(errno));

    ccnxMetaMessage = athenaTransportLinkAdapter_Receive(athenaTransportLinkAdapter, &resultVector, 1);
    assertNull(resultVector, "athenaTransportLinkAdapter_Receive should have failed");

    closeResult = athenaTransportLinkAdapter_CloseByName(athenaTransportLinkAdapter, "UDP_1");
    assertTrue(closeResult == 0, "athenaTransportLinkAdapter_CloseByName failed (%s)", strerror(errno));

    athenaTransportLinkAdapter_Destroy(&athenaTransportLinkAdapter);
}
LONGBOW_TEST_CASE(Global, athenaTransportLinkModuleUDP_MTU)
{
    PARCURI *connectionURI;
    const char *result;
    AthenaTransportLinkAdapter *athenaTransportLinkAdapter = athenaTransportLinkAdapter_Create(_removeLink, NULL);
    assertNotNull(athenaTransportLinkAdapter, "athenaTransportLinkAdapter_Create returned NULL");

    connectionURI = parcURI_Parse("udp://127.0.0.1:40000/Listener/name=UDPListener/mtu=");
    result = athenaTransportLinkAdapter_Open(athenaTransportLinkAdapter, connectionURI);
    assertTrue(result == NULL, "athenaTransportLinkAdapter_Open failed to detect improper MTU (%s)", strerror(errno));
    parcURI_Release(&connectionURI);

    connectionURI = parcURI_Parse("udp://127.0.0.1:40000/Listener/name=UDPListener/mtu=20");
    result = athenaTransportLinkAdapter_Open(athenaTransportLinkAdapter, connectionURI);
    assertTrue(result != NULL, "athenaTransportLinkAdapter_Open failed (%s)", strerror(errno));
    parcURI_Release(&connectionURI);

    connectionURI = parcURI_Parse("udp://127.0.0.1:40000/name=UDP_1/mtu=20");
    result = athenaTransportLinkAdapter_Open(athenaTransportLinkAdapter, connectionURI);
    assertTrue(result != NULL, "athenaTransportLinkAdapter_Open failed (%s)", strerror(errno));
    parcURI_Release(&connectionURI);

    athenaTransportLinkAdapter_Poll(athenaTransportLinkAdapter, 0);

    CCNxName *name = ccnxName_CreateFromCString("lci:/foo/bar");
    CCNxMetaMessage *ccnxMetaMessage = ccnxInterest_CreateSimple(name);
    ccnxName_Release(&name);

    PARCBitVector *sendVector = parcBitVector_Create();

    int linkId = athenaTransportLinkAdapter_LinkNameToId(athenaTransportLinkAdapter, "UDP_1");
    parcBitVector_Set(sendVector, linkId);

    athena_EncodeMessage(ccnxMetaMessage);
    PARCBitVector *resultVector;
    resultVector = athenaTransportLinkAdapter_Send(athenaTransportLinkAdapter, ccnxMetaMessage, sendVector);
    assertTrue(parcBitVector_NumberOfBitsSet(resultVector) == 0, "athenaTransportLinkAdapter_Send should have failed");
    assertTrue(errno == EMSGSIZE, "athenaTransportLinkAdapter_Send should have failed with EMSGSIZE (%d): %s", errno, strerror(errno));
    parcBitVector_Release(&resultVector);
    ccnxMetaMessage_Release(&ccnxMetaMessage);
    parcBitVector_Release(&sendVector);

    usleep(1000);

    ccnxMetaMessage = athenaTransportLinkAdapter_Receive(athenaTransportLinkAdapter, &resultVector, 0);
    assertNull(ccnxMetaMessage, "athenaTransportLinkAdapter_Receive should have failed");

    int closeResult = athenaTransportLinkAdapter_CloseByName(athenaTransportLinkAdapter, "UDPListener");
    assertTrue(closeResult == 0, "athenaTransportLinkAdapter_CloseByName failed (%s)", strerror(errno));

    closeResult = athenaTransportLinkAdapter_CloseByName(athenaTransportLinkAdapter, "UDP_1");
    assertTrue(closeResult == 0, "athenaTransportLinkAdapter_CloseByName failed (%s)", strerror(errno));

    athenaTransportLinkAdapter_Destroy(&athenaTransportLinkAdapter);
}
LONGBOW_TEST_CASE(Global, athenaTransportLinkAdapter_OpenPollClose)
{
    PARCURI *connectionURI;
    const char *result;
    AthenaTransportLinkAdapter *athenaTransportLinkAdapter = athenaTransportLinkAdapter_Create(_removeLink, NULL);
    assertNotNull(athenaTransportLinkAdapter, "athenaTransportLinkAdapter_Create returned NULL");

    _LoadModule(athenaTransportLinkAdapter, "TCP");

    result = athenaTransportLinkAdapter_Open(athenaTransportLinkAdapter, NULL);
    assertTrue(result == NULL, "athenaTransportLinkAdapter_Open succeeded for NULL URI");

    connectionURI = parcURI_Parse("unknown://127.0.0.1:50200/name=TCP_0");
    result = athenaTransportLinkAdapter_Open(athenaTransportLinkAdapter, connectionURI);
    assertTrue(result == NULL, "athenaTransportLinkAdapter_Open succeeded for Unknown module");
    parcURI_Release(&connectionURI);

    connectionURI = parcURI_Parse("tcp://127.0.0.1:50200/nam=");
    result = athenaTransportLinkAdapter_Open(athenaTransportLinkAdapter, connectionURI);
    assertTrue(result == NULL, "athenaTransportLinkAdapter_Open succeeded for module with bad argument");
    parcURI_Release(&connectionURI);

    connectionURI = parcURI_Parse("tcp://127.0.0.1:50200/listener/name=TCPListener");
    result = athenaTransportLinkAdapter_Open(athenaTransportLinkAdapter, connectionURI);
    assertTrue(result != NULL, "athenaTransportLinkAdapter_Open failed (%s)", strerror(errno));
    parcURI_Release(&connectionURI);

    connectionURI = parcURI_Parse("tcp://127.0.0.1:50200/listener/name=TCPListener");
    result = athenaTransportLinkAdapter_Open(athenaTransportLinkAdapter, connectionURI);
    assertTrue(result == NULL, "athenaTransportLinkAdapter_Open succeeded for duplicate listener name");
    parcURI_Release(&connectionURI);

    connectionURI = parcURI_Parse("tcp://127.0.0.1:50200/name=TCP_0");
    result = athenaTransportLinkAdapter_Open(athenaTransportLinkAdapter, connectionURI);
    assertTrue(result != NULL, "athenaTransportLinkAdapter_Open failed (%s)", strerror(errno));
    parcURI_Release(&connectionURI);

    connectionURI = parcURI_Parse("tcp://127.0.0.1:50200/name=TCP_0");
    result = athenaTransportLinkAdapter_Open(athenaTransportLinkAdapter, connectionURI);
    assertTrue(result == NULL, "athenaTransportLinkAdapter_Open succeeded for duplicate link name");
    parcURI_Release(&connectionURI);

    athenaTransportLinkAdapter_Poll(athenaTransportLinkAdapter, 0);

    int closeResult = athenaTransportLinkAdapter_CloseByName(athenaTransportLinkAdapter, "TCP_0");
    assertTrue(closeResult == 0, "athenaTransportLinkAdapter_CloseByName failed (%s)", strerror(errno));

    closeResult = athenaTransportLinkAdapter_CloseByName(athenaTransportLinkAdapter, "TCP_999");
    assertTrue(closeResult == -1, "athenaTransportLinkAdapter_CloseByName succeeded for unknown link TCP_999");

    athenaTransportLinkAdapter_Destroy(&athenaTransportLinkAdapter);
}
CCNxMetaMessage *
athenaTransportLinkAdapter_Receive(AthenaTransportLinkAdapter *athenaTransportLinkAdapter,
                                   PARCBitVector **resultVector, int timeout)
{
    int linkId;
    *resultVector = parcBitVector_Create();

    // Traverse instance list starting from where we last left off.
    linkId = athenaTransportLinkAdapter->nextLinkToRead;
    CCNxMetaMessage *ccnxMetaMessage = _retrieve_next_message(athenaTransportLinkAdapter, athenaTransportLinkAdapter->instanceList, &linkId);
    if (ccnxMetaMessage) {
        parcBitVector_Set(*resultVector, linkId);
        athenaTransportLinkAdapter->nextLinkToRead = linkId + 1;
        athenaTransportLinkAdapter->stats.messageReceived++;
        return ccnxMetaMessage;
    }

    // Once the instance list is clear, traverse the entire listener list
    ccnxMetaMessage = _retrieve_next_message(athenaTransportLinkAdapter, athenaTransportLinkAdapter->listenerList, NULL);
    assertNull(ccnxMetaMessage, "listener returned an unexpected message");

    // Last instance event has been serviced, poll all modules.
    athenaTransportLinkAdapter_Poll(athenaTransportLinkAdapter, timeout);

    // Traverse the entire listener list (could potentially populate other instances)
    ccnxMetaMessage = _retrieve_next_message(athenaTransportLinkAdapter, athenaTransportLinkAdapter->listenerList, NULL);
    assertNull(ccnxMetaMessage, "listener returned an unexpected message");

    // Search instance list from the beginning.
    athenaTransportLinkAdapter->nextLinkToRead = 0;
    linkId = athenaTransportLinkAdapter->nextLinkToRead;
    ccnxMetaMessage = _retrieve_next_message(athenaTransportLinkAdapter, athenaTransportLinkAdapter->instanceList, &linkId);
    if (ccnxMetaMessage) {
        parcBitVector_Set(*resultVector, linkId);
        athenaTransportLinkAdapter->nextLinkToRead = linkId + 1;
        athenaTransportLinkAdapter->stats.messageReceived++;
        return ccnxMetaMessage;
    }

    parcBitVector_Release(resultVector);
    errno = EAGAIN;
    return NULL;
}
LONGBOW_TEST_CASE(Global, athenaTransportLinkAdapter_AddRemoveLink)
{
    PARCURI *connectionURI;
    const char *result;
    AthenaTransportLinkAdapter *athenaTransportLinkAdapter = athenaTransportLinkAdapter_Create(_removeLink, NULL);
    assertNotNull(athenaTransportLinkAdapter, "athenaTransportLinkAdapter_Create returned NULL");

    _LoadModule(athenaTransportLinkAdapter, "TCP");

    connectionURI = parcURI_Parse("tcp://127.0.0.1:50200/Listener/name=TCP_0");
    result = athenaTransportLinkAdapter_Open(athenaTransportLinkAdapter, connectionURI);
    assertTrue(result != NULL, "athenaTransportLinkAdapter_Open failed (%s)", strerror(errno));
    parcURI_Release(&connectionURI);

    athenaTransportLinkAdapter_Poll(athenaTransportLinkAdapter, 0);

    int closeResult = athenaTransportLinkAdapter_CloseByName(athenaTransportLinkAdapter, "TCP_0");
    assertTrue(closeResult == 0, "athenaTransportLinkAdapter_CloseByName failed (%s)", strerror(errno));

    athenaTransportLinkAdapter_Destroy(&athenaTransportLinkAdapter);
}