(file) Return to test_httpclient.cpp CVS log (file) (dir) Up to [OMI] / omi / protocol / tests

File: [OMI] / omi / protocol / tests / Attic / test_httpclient.cpp (download)
Revision: 1.1.1.1 (vendor branch), Wed May 30 21:47:49 2012 UTC (12 years, 1 month ago) by mike
Branch: TOG
CVS Tags: OMI_1_0_2_Branch, OMI_1_0_2, OMI_1_0_1_PRE, OMI_1_0_1, OMI_1_0_0
Changes since 1.1: +0 -0 lines
Initial Import

/*
**==============================================================================
**
** Open Management Infrastructure (OMI)
**
** Copyright (c) Microsoft Corporation
** 
** 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 
**
** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 
** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 
** MERCHANTABLITY OR NON-INFRINGEMENT. 
**
** See the Apache 2 License for the specific language governing permissions 
** and limitations under the License.
**
**==============================================================================
*/

#include <vector>
#include <map>
#include <cstdlib>
#include <ut/ut.h>
#include <unittest/utils.h>
#include <protocol/httpclient.h>
#include <protocol/http.h>
#include <protocol/thread.h>
#include <base/result.h>

using namespace std;

/*********************************** http server ***************************/

/* local data */
static  Http* s_http;
static bool s_stop;
static ThreadHandle s_t;
static MI_Uint16 PORT = ut::getUnittestPortNumber() + 10;
static string s_contentType;
static string s_charset;
static string s_content;
static string s_response;
static bool s_delayServerResponse = false;

// received data
static int s_httpCode;
static map< string, string > s_headers;
static string s_contentReceivedFromServer;
static int s_cxxError;

static bool s_httpResponseReceived;

#if defined(_MSC_VER)
#undef BEGIN_EXTERNC
#undef END_EXTERNC
#define BEGIN_EXTERNC
#define END_EXTERNC
#endif

static void setUp()
{
    s_httpResponseReceived = false;
    s_response = "";
    s_contentType = "";
    s_delayServerResponse = false;

    s_httpCode = 0;
    s_headers.clear();
    s_contentReceivedFromServer.clear();
    s_cxxError = -1;
}

static void cleanup()
{
}

 /* helper functions */
BEGIN_EXTERNC
static void* MI_CALL _HTTPServerProc(void* )
{
    Sock_Start();
    // pump messages
    for (; !s_stop; )
        Http_Run( s_http, 1000 );

    Sock_Stop();
    return 0;
}
END_EXTERNC

BEGIN_EXTERNC
static void _StartHTTP_Server(
    HttpCallbackOnNewConnection callbackOnNewConnection,
    HttpCallbackOnCloseConnection callbackOnCloseConnection,
    HttpCallbackOnRequest callbackOnRequest,
    void* callbackData,
    const HttpOptions* options = 0)
{
    /* create a server */
    UT_ASSERT( MI_RESULT_OK == Http_New_Server(
        &s_http, 0, PORT, PORT + 1,
        callbackOnNewConnection,
        callbackOnCloseConnection,
        callbackOnRequest, callbackData) );

    if (options)
    {
        UT_ASSERT( MI_RESULT_OK == Http_SetOptions(
            s_http, options) );
    }

    /* create a thread for message consumption */
    s_stop = false;

    UT_ASSERT(MI_RESULT_OK == Thread_Create(
        _HTTPServerProc, 0, &s_t));

}
END_EXTERNC

BEGIN_EXTERNC
static void _StopHTTP_Server()
{
    s_stop = true;
    UT_ASSERT(MI_RESULT_OK == Thread_Destroy( s_t, MI_TRUE ));
    UT_ASSERT( MI_RESULT_OK == Http_Delete(s_http) );

    s_t = 0;
    s_http = 0;
    s_stop = false;
}
END_EXTERNC

BEGIN_EXTERNC
static void _HttpCallbackOnNewConnection(
    Http* /*http*/,
    void* /*callbackData*/,
    void* httpConnectionHandle,
    void** connectionData)
{
    *connectionData = httpConnectionHandle;
}
END_EXTERNC

BEGIN_EXTERNC
static void _HttpCallbackOnCloseConnection(
    Http* /*http*/,
    void* /*callbackData*/,
    void* /*connectionData*/)
{
}
END_EXTERNC

BEGIN_EXTERNC
static void _HttpCallbackOnRequest(
    Http* http,
    void* /*callbackData*/,
    void* connectionData,
    void* httpConnectionHandle,
    const HttpHeaders* headers,
    Page** page)
{
    UT_ASSERT(httpConnectionHandle == connectionData);

//    printf("cbt, %s\n", headers->authorization);

    if (headers->contentType)
        s_contentType = headers->contentType;
    else
        s_contentType = "";

    if (headers->charset)
        s_charset = headers->charset;
    else
        s_charset = "";

    if (page && *page)
        s_content = string( (char*) ((*page)+1), ((char*)((*page)+1)) + (*page)->u.s.size);
    else
        s_content.clear();

    Page* rsp = (Page*)malloc(sizeof(Page) + s_response.size());
    
    UT_ASSERT(rsp);

    rsp->u.s.size = s_response.size();
    memcpy(rsp+1, s_response.c_str(), s_response.size());

    if (s_delayServerResponse)
        ut::sleep_ms(175);

    Http_SendResponse( http, httpConnectionHandle, HTTP_ERROR_CODE_OK, &rsp );

    if (rsp )
        free(rsp);
}
END_EXTERNC


/************************************* http client **********************/



BEGIN_EXTERNC
static void _HttpClientCallbackOnStatus(
    HttpClient* http,
    void* callbackData,
    MI_Result result)
{
    MI_UNUSED(http);
    MI_UNUSED(callbackData);
    MI_UNUSED(result);
    s_httpResponseReceived = true;

}

static MI_Boolean _HttpClientCallbackOnResponse(
    HttpClient* http,
    void* callbackData,
    const HttpClientResponseHeader* headers,
    MI_Sint64 contentSize,
    MI_Boolean  lastChunk,
    Page** data)
{
    MI_UNUSED(http);
    MI_UNUSED(callbackData);
    MI_UNUSED(headers);
    MI_UNUSED(contentSize);
    MI_UNUSED(lastChunk);

    if (headers)
    {
        s_httpCode = headers->httpError;
        for (unsigned int i = 0; i < headers->sizeHeaders; i++)
        {
            s_headers[headers->headers[i].name] = headers->headers[i].value;
        }
    }

    if (data && *data)
    {
        s_contentReceivedFromServer +=
            string( (char*) ((*data)+1), ((char*)((*data)+1)) + (*data)->u.s.size);
    }

    return MI_TRUE;
}
END_EXTERNC


/* Simplified http client for chunked stuff testing */
struct ThreadSrvParam
{
    string messageToSend;
    size_t  bytesToSendPerOperation;
    bool started;

    ThreadSrvParam():
        bytesToSendPerOperation(0),
        started(false)
    {
    }
};

/* simple http client */
static void* MI_CALL _http_server_proc(void* param)
{
    ThreadSrvParam* p = (ThreadSrvParam*)param;

    Addr addr;
    Sock sock, listener;
    MI_Result r;

    Sock_Start();

    // Initialize address (connect using loopback).
    Addr_InitAny(&addr, PORT+2);

    UT_ASSERT_EQUAL(Sock_CreateListener(&listener, &addr), MI_RESULT_OK);
    UT_ASSERT_EQUAL(Sock_SetBlocking(listener, MI_FALSE), MI_RESULT_OK);

    p->started = true;

    // accept incoming request
    for (int i = 0; ; i++)
    {
        // check if we waited too long
        UT_ASSERT(i<1000);

        r = Sock_Accept(listener, &sock, &addr);

        if (MI_RESULT_WOULD_BLOCK == r)
        {
            ut::sleep_ms(1);
            continue;
        }

        UT_ASSERT_EQUAL(r, MI_RESULT_OK);
        break;
    }

    // close listener
    Sock_Close(listener);


    // read and ignore http request
    char r_buf[1024];
    size_t read = 0;
    r = Sock_Read(sock, r_buf, sizeof(r_buf), &read);
    
    if (r) printf("s,r: %d, err %d\n", (int)read, Sock_GetLastError());

    // send pre-defined response

    size_t sent = 0;
    size_t size_left = p->messageToSend.size();
    const char* buf = p->messageToSend.c_str();

    while ( size_left )
    {
        ut::sleep_ms( 1 );

        size_t wantToSend = min(p->bytesToSendPerOperation, size_left);
        r = Sock_Write(sock, buf, wantToSend, &sent);

        //printf("size_left %d, r %d, sent %d, want-send %d\n", size_left, r, sent, wantToSend);
        if ( r != MI_RESULT_OK)
        {
            printf("size_left %d, r %d, want write %d, sent %d, le %d\n", (int)size_left, (int)r, (int)wantToSend, (int)sent, Sock_GetLastError());
            ut::sleep_ms( 7000 );
        }

        UT_ASSERT(r == MI_RESULT_OK);
//        printf("s: %d\n", (int)sent);
        size_left -= sent;
        buf += sent;
    }

    Sock_Close(sock);

    Sock_Stop();
    return 0;
}

BEGIN_EXTERNC
static void* MI_CALL http_server_proc(void* param)
{
    try
    {
        return _http_server_proc(param);
    }
    catch (ut::UnittestException ex)
    {
        ex.m_testcase = "--http_server_proc"; testFailed(ex);
    }  
    return 0;
}
END_EXTERNC



static void TestHttpClient_BasicOperations()
{
    HttpClient* http = 0;
    const char* header_strings[] = {
        "Content-Type: text/html",
        //"User-Agent: xplat http cleint" ,
        "Host: host"
    };

    /* content to send to the client */
    s_response = "Test";

    HttpClientRequestHeaders headers = {
        header_strings,
        MI_COUNT(header_strings) };

    UT_ASSERT_EQUAL(MI_RESULT_OK,
        HttpClient_New_Connector(&http, 0, "127.0.0.1", PORT, MI_FALSE, 
        _HttpClientCallbackOnStatus, 
        _HttpClientCallbackOnResponse, 0));

    UT_ASSERT_EQUAL(MI_RESULT_OK,
        HttpClient_StartRequest(http, "GET", "/", &headers, 0));

    for (int i = 0; i < 10000 && !s_httpResponseReceived; i++)
        HttpClient_Run(http, 1000);

    // verify results:
    UT_ASSERT_EQUAL(s_httpCode, 200);
    UT_ASSERT_EQUAL(s_headers["Content-Type"], "application/soap+xml;charset=UTF-8");
    UT_ASSERT_EQUAL(s_contentReceivedFromServer, string("Test"));
    UT_ASSERT_EQUAL(s_contentType, string("text/html"));

    UT_ASSERT_EQUAL(MI_RESULT_OK,
        HttpClient_Delete(http));

    http = 0;


}

static void TestHttpClient_BasicOperations_https()
{
}

static void _runClientWithSimplifiedServer(ThreadSrvParam& param)
{
    HttpClient* http = 0;

    const char* header_strings[] = {
        "Content-Type: text/html"
    };

    /* create a server */
    ThreadHandle t;

    UT_ASSERT(MI_RESULT_OK == Thread_Create(
        http_server_proc, &param, &t));

    for (int i = 0; !param.started; i++)
    {
        // check if we waited too long
        UT_ASSERT(i<1000);

        ut::sleep_ms(1);
    }

    HttpClientRequestHeaders headers = {
        header_strings,
        MI_COUNT(header_strings) };

    
    UT_ASSERT_EQUAL(MI_RESULT_OK,
        HttpClient_New_Connector(&http, 0, "127.0.0.1", PORT+2, MI_FALSE, 
        _HttpClientCallbackOnStatus, 
        _HttpClientCallbackOnResponse, 0));

    
    UT_ASSERT_EQUAL(MI_RESULT_OK,
        HttpClient_StartRequest(http, "GET", "/", &headers, 0));

    for (int i = 0; i < 10000 && !s_httpResponseReceived; i++)
        HttpClient_Run(http, 1000);


    // wait for completion and check that
    UT_ASSERT(MI_RESULT_OK == Thread_Destroy( t, MI_TRUE ));

    // free client pointer
    UT_ASSERT_EQUAL(MI_RESULT_OK,
        HttpClient_Delete(http));

    http = 0;

}

static void TestHttpClient_ChunkedResponse()
{
    ThreadSrvParam param;

    /* content to send to the client */
    param.messageToSend = 
    /* header */
    "HTTP/1.1 200 OK\r\n"   
    "transfer-encoding: chunked\r\n"
    "Connection: Keep-Alive\r\n"
    "Content-Type: application/soap+xml;charset=UTF-8\r\n"
    "\r\n"

    /* chunk 1 */
    "1 \r\n"
    "T\r\n"
        
    /* chunk 2 */
    "3 \r\n"
    "est\r\n"
        
    /* last chunk */
    "0 \r\n"
    "\r\n"
        ;
    param.bytesToSendPerOperation = 10240;

    _runClientWithSimplifiedServer(param);

    // verify results:
    UT_ASSERT_EQUAL(s_httpCode, 200);
    UT_ASSERT_EQUAL(s_headers["Content-Type"], "application/soap+xml;charset=UTF-8");
    UT_ASSERT_EQUAL(s_contentReceivedFromServer, string("Test"));

}

static void TestHttpClient_ChunkedResponseByOneByte()
{
    ThreadSrvParam param;

    /* content to send to the client */
    param.messageToSend = 
    /* header */
    "HTTP/1.1 200 OK\r\n"   
    "transfer-encoding: chunked\r\n"
    "Connection: Keep-Alive\r\n"
    "Content-Type: application/soap+xml;charset=UTF-8\r\n"
    "\r\n"

    /* chunk 1 - 17 bytes */
    "11 \r\n"
    "1234567890abcdefT\r\n"
        
    /* chunk 2 - 13 bytes */
    "d \r\n"
    "est1234567890\r\n"
        
    /* last chunk */
    "0 \r\n"
    "\r\n"
        ;
    param.bytesToSendPerOperation = 1;

    _runClientWithSimplifiedServer(param);

    // verify results:
    UT_ASSERT_EQUAL(s_httpCode, 200);
    UT_ASSERT_EQUAL(s_headers["Content-Type"], "application/soap+xml;charset=UTF-8");
    UT_ASSERT_EQUAL(s_contentReceivedFromServer, string("1234567890abcdefTest1234567890"));

}

static void RunTests()
{
    Sock_Start();
    _StartHTTP_Server(        
        _HttpCallbackOnNewConnection,
        _HttpCallbackOnCloseConnection,
        _HttpCallbackOnRequest, 
        0);


    UT_TEST(TestHttpClient_BasicOperations);
    UT_TEST(TestHttpClient_BasicOperations_https);
    UT_TEST(TestHttpClient_ChunkedResponse);
    UT_TEST(TestHttpClient_ChunkedResponseByOneByte);

    _StopHTTP_Server();
    Sock_Stop();
}

UT_ENTRY_POINT(RunTests);

ViewCVS 0.9.2