void test_KineticSession_Create_should_allocate_and_destroy_KineticConnections(void)
{
    KineticSession session;
    memset(&session, 0, sizeof(session));

    KineticCountingSemaphore_Create_ExpectAndReturn(KINETIC_MAX_OUTSTANDING_OPERATIONS_PER_SESSION, &Semaphore);

    KineticStatus status = KineticSession_Create(&session, &Client);

    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
    TEST_ASSERT_FALSE(session.connected);
    TEST_ASSERT_EQUAL(-1, session.socket);
    TEST_ASSERT_EQUAL_INT64(0, session.sequence);
    TEST_ASSERT_EQUAL_INT64(0, session.connectionID);

    KineticCountingSemaphore_Destroy_Expect(&Semaphore);
    KineticAllocator_FreeSession_Expect(&session);

    status = KineticSession_Destroy(&session);

    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
}
void test_KineticClient_CreateSession_should_return_KINETIC_STATUS_HOST_EMPTY_upon_NULL_host(void)
{
    KineticClient client;
    ByteArray key = ByteArray_CreateWithCString("some_key");
    KineticSessionConfig config = {
        .host = "",
        .hmacKey = key,
    };
    KineticSession* session = NULL;

    KineticStatus status = KineticClient_CreateSession(&config, &client, &session);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_HOST_EMPTY, status);
}

void test_KineticClient_CreateSession_should_return_KINETIC_STATUS_HMAC_REQUIRED_upon_NULL_HMAC_key(void)
{
    KineticClient client;
    ByteArray key = {.len = 4, .data = NULL};
    KineticSessionConfig config = {
        .host = "somehost.com",
        .hmacKey = key,
    };
    KineticSession* session;

    KineticStatus status = KineticClient_CreateSession(&config, &client, &session);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_HMAC_REQUIRED, status);
}

void test_KineticClient_CreateSession_should_return_false_upon_empty_HMAC_key(void)
{
    KineticClient client;
    uint8_t keyData[] = {0, 1, 2, 3};
    ByteArray key = {.len = 0, .data = keyData};
    KineticSessionConfig config = {
        .host = "somehost.com",
        .hmacKey = key,
    };
    KineticSession* session;

    KineticStatus status = KineticClient_CreateSession(&config, &client, &session);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_HMAC_REQUIRED, status);
}

void test_KineticClient_CreateSession_should_return_MEMORY_ERROR_if_unable_to_allocate_a_session(void)
{
    KineticClient client;
    client.bus = &MessageBus;
    KineticSessionConfig config = {
        .host = "somehost.com",
        .hmacKey = ByteArray_CreateWithCString("some_key"),
    };
    KineticSession* session = NULL;

    KineticAllocator_NewSession_ExpectAndReturn(&MessageBus, &config, NULL);

    KineticStatus status = KineticClient_CreateSession(&config, &client, &session);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_MEMORY_ERROR, status);
}

void test_KineticClient_CreateSession_should_return_KINETIC_STATUS_MEMORY_ERROR_upon_NULL_connection(void)
{
    KineticClient client = {
        .bus = &MessageBus,
    };
    KineticSessionConfig config = {
        .host = "somehost.com",
        .hmacKey = ByteArray_CreateWithCString("some_key"),
    };
    KineticSession* session = NULL;

    KineticAllocator_NewSession_ExpectAndReturn(&MessageBus, &config, NULL);

    KineticStatus status = KineticClient_CreateSession(&config, &client, &session);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_MEMORY_ERROR, status);
    TEST_ASSERT_NULL(session);
}

void test_KineticClient_CreateSession_should_return_status_from_a_failed_connection(void)
{
    KineticClient client;
    client.bus = &MessageBus;
    KineticSessionConfig config = {
        .host = "somehost.com",
        .hmacKey = ByteArray_CreateWithCString("some_key"),
    };
    KineticSession* session;

    KineticAllocator_NewSession_ExpectAndReturn(&MessageBus, &config, &Session);
    KineticSession_Create_ExpectAndReturn(&Session, &client, KINETIC_STATUS_SUCCESS);
    KineticSession_Connect_ExpectAndReturn(&Session, KINETIC_STATUS_HMAC_REQUIRED);
    KineticAllocator_FreeSession_Expect(&Session);

    KineticStatus status = KineticClient_CreateSession(&config, &client, &session);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_HMAC_REQUIRED, status);
}


void test_KineticClient_DestroySession_should_disconnect_and_free_the_connection_associated_with_handle(void)
{
    KineticSession_Disconnect_ExpectAndReturn(&Session, KINETIC_STATUS_SUCCESS);
    KineticSession_Destroy_ExpectAndReturn(&Session, KINETIC_STATUS_SUCCESS);
    KineticStatus status = KineticClient_DestroySession(&Session);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SUCCESS, status);
}

void test_KineticClient_DestroySession_should_return_status_from_KineticSession_upon_faileure(void)
{
    KineticSession_Disconnect_ExpectAndReturn(&Session, KINETIC_STATUS_SESSION_INVALID);
    KineticSession_Destroy_ExpectAndReturn(&Session, KINETIC_STATUS_SUCCESS);
    KineticStatus status = KineticClient_DestroySession(&Session);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_SESSION_INVALID, status);
}

void test_KineticClient_GetTerminationStatus_should_delegate_to_session(void)
{
    KineticSession_GetTerminationStatus_ExpectAndReturn(&Session, KINETIC_STATUS_DATA_ERROR);
    KineticStatus status = KineticClient_GetTerminationStatus(&Session);
    TEST_ASSERT_EQUAL_KineticStatus(KINETIC_STATUS_DATA_ERROR, status);
}