LONGBOW_TEST_CASE(Global, rtaComponent_PutMessage_ClosedConnection)
{
    TestData *data = longBowTestCase_GetClipBoardData(testCase);

    rtaConnection_SetState(data->connection, CONN_CLOSED);

    // Create the TransportMessage to put on the queue
    TransportMessage *tm = trafficTools_CreateTransportMessageWithDictionaryControl(data->connection, CCNxTlvDictionary_SchemaVersion_V1);

    // Send it down from the API connector to the Testing Lower component
    PARCEventQueue *outputQueue = rtaComponent_GetOutputQueue(data->connection, API_CONNECTOR, RTA_DOWN);

    int success = rtaComponent_PutMessage(outputQueue, tm);
    assertFalse(success, "Error putting message on API Connector's down queue");

    // check that we got it
    PARCEventQueue *inputQueue = rtaComponent_GetOutputQueue(data->connection, TESTING_LOWER, RTA_UP);

    TransportMessage *test_tm = rtaComponent_GetMessage(inputQueue);
    assertNull(test_tm, "Should have returned NULL on a closed connection");

    // The transport message was destroyed by PutMessage because the connection
    // was closed.  Don't need to destroy the transport message.

    // set state back to OPEN so the connection is properly disposed of
    rtaConnection_SetState(data->connection, CONN_OPEN);
}
static TransportMessage *
sendUp(TestData *data, TransportMessage *tm_going_down)
{
    PARCEventQueue *out = rtaProtocolStack_GetPutQueue(data->mock->stack, TESTING_UPPER, RTA_DOWN);
    PARCEventQueue *in = rtaProtocolStack_GetPutQueue(data->mock->stack, TESTING_LOWER, RTA_UP);

    rtaComponent_PutMessage(in, tm_going_down);
    // turn the handle enough times, the message will pass all the way out the bottom
    rtaFramework_NonThreadedStepCount(data->mock->framework, 10);
    return rtaComponent_GetMessage(out);
}
LONGBOW_TEST_CASE(Global, rtaComponent_PutMessage_OpenConnection)
{
    TestData *data = longBowTestCase_GetClipBoardData(testCase);

    // Create the TransportMessage to put on the queue
    TransportMessage *tm = trafficTools_CreateTransportMessageWithDictionaryControl(data->connection, CCNxTlvDictionary_SchemaVersion_V1);

    // Send it down from the API connector to the Testing Lower component
    PARCEventQueue *outputQueue = rtaComponent_GetOutputQueue(data->connection, API_CONNECTOR, RTA_DOWN);

    int success = rtaComponent_PutMessage(outputQueue, tm);
    assertTrue(success, "Error putting message on API Connector's down queue");

    // check that we got it
    PARCEventQueue *inputQueue = rtaComponent_GetOutputQueue(data->connection, TESTING_LOWER, RTA_UP);

    TransportMessage *test_tm = rtaComponent_GetMessage(inputQueue);
    assertTrue(test_tm == tm, "Got wrong message, got %p expected %p", (void *) test_tm, (void *) tm);

    transportMessage_Destroy(&tm);
}
/**
 * Calls the release() function of all components.
 * Drains all the component queues.
 *
 * This is called from rtaFramework_DestroyStack, who is responsible for closing
 * all the connections in it before calling this.
 *
 * Example:
 * @code
 * <#example#>
 * @endcode
 */
void
rtaProtocolStack_Destroy(RtaProtocolStack **stackPtr)
{
    RtaProtocolStack *stack;

    assertNotNull(stackPtr, "%s called with null pointer to stack\n", __func__);

    stack = *stackPtr;
    assertNotNull(stack, "%s called with null stack dereference\n", __func__);

    if (DEBUG_OUTPUT) {
        printf("%s stack_id %d destroying stack %p\n",
               __func__,
               stack->stack_id,
               (void *) stack);
    }

    stack->stateChangeEventsEnabled = false;

    // call all the release functions
    for (int i = 0; i < stack->component_count; i++) {
        RtaComponents comp = stack->components[i];
        if (stack->component_ops[comp].release != NULL &&
            stack->component_ops[comp].release(stack) != 0) {
            fprintf(stderr, "%s component %d failed release\n", __func__, i);
            abort();
        }
    }

    for (int i = 0; i < MAX_STACK_DEPTH; i++) {
        TransportMessage *tm;
        while ((tm = rtaComponent_GetMessage(parcEventQueue_GetConnectedUpQueue(stack->queue_pairs[i]))) != NULL) {
            assertFalse(1, "%s we should never execute the body, it should just drain\n", __func__);
        }

        while ((tm = rtaComponent_GetMessage(parcEventQueue_GetConnectedDownQueue(stack->queue_pairs[i]))) != NULL) {
            assertFalse(1, "%s we should never execute the body, it should just drain\n", __func__);
        }

        if (DEBUG_OUTPUT) {
            printf("%9" PRIu64 " %s destroy buffer pair %p <-> %p\n",
                   rtaFramework_GetTicks(rtaProtocolStack_GetFramework(stack)),
                   __func__,
                   (void *) parcEventQueue_GetConnectedUpQueue(stack->queue_pairs[i]),
                   (void *) parcEventQueue_GetConnectedDownQueue(stack->queue_pairs[i]));
        }

        parcEventQueue_DestroyConnectedPair(&(stack->queue_pairs[i]));
    }

    for (int i = 0; i < LAST_COMPONENT; i++) {
        if (stack->component_queues[i]) {
            parcMemory_Deallocate((void **) &(stack->component_queues[i]));
        }
    }

    for (int i = 0; i < LAST_COMPONENT; i++) {
        rtaComponentStats_Destroy(&stack->stack_stats[i]);
    }


    parcJSON_Release(&stack->params);
    memset(stack, 0, sizeof(RtaProtocolStack));

    parcMemory_Deallocate((void **) &stack);
    *stackPtr = NULL;
}